• Helm으로 손쉽게 Kubernetes에 애플리케이션 배포하기


    쿠버네티스에 배포하는 모든 종류의 리소스 (디플로이먼트, 서비스, 인그레스 등)은 모두 yaml 파일에 작성된 폼을 기반으로 구성된다. 사용자가 할 일은 열심히 yaml 파일을 작성한 후, kubectl apply 명령어로 파일을 적용시키기만 하면 끝.

    그런데, 본격적으로 쿠버네티스에 이것저것 올리다 보면 뭔가 아쉬울 때가 있다. 한 애플리케이션을 위해 여러 yaml 파일을 적용해야 하는 경우, 비슷한 뼈대를 바탕으로 해 다른 일을 처리하는 애플리케이션을 만드는 경우 등 생각보다 기본 yaml 파일을 단순히 적용하는 것 이상의 “무언가”에 갈증을 느끼게 된다.

    오늘 들고 온 Helm이 바로 여러분이 찾던 그 “무언가” 다. 너무나도 매끄럽게 잘 작동하는 패키지 매니저로서, Helm을 위해 미리 준비한 Helm Chart만 있으면 마치 .exe 프로그램을 설치하듯, 쿠버네티스라는 내 컴퓨터에 내 애플리케이션을 뚝딱 설치할 수 있다.

    깨끗한 쿠버네티스 클러스터를 준비한 후, 아래 글을 쭉 따라와보자. 곧 Helm의 매력에 푹 빠질 것이다.

    Helm 설치하기

    마치 쿠버네티스 클러스터에 접근하기 위해서는 kubectl이 필요하듯, Helm을 쿠버네티스 클러스터에 설치하고 애플리케이션을 배포하기 위해서는 Helm 클라이언트가 필요하다.

    macOS에서는 brew를 통해 아래 명령어로 간단히 설치할 수 있다. 다른 OS에서는 이 가이드 를 참고하자.

    만약 로컬에 kubectl이 설치되어 있지 않을 경우, 아래 명령어가 kubectl까지 같이 설치합니다. 설치되어 있을 경우라도 최신 버전으로 자동으로 업데이트 하니 만약 구버전 kubectl 또는 helm이 필요할 경우 특정 버전을 지정하여 설치하시기 바랍니다.

    brew install kubernetes-helm
    

    설치가 완료된 후 helm version 명령어를 통해 정상적으로 설치가 진행되었는지 꼭 확인하자. 지금은 서버 측에 helm이 준비되지 않아 Client:로 시작하는 로컬 Helm 정보만 출력될 것인데, 정상이다.

    클라이언트가 제대로 준비되었다면, 이제 쿠버네티스에 Helm을 설치할 차례다. HelmTiller라는 특수한 Pod를 통해 쿠버네티스 위에서 리소스를 생성하고 지우는데, 자유롭게 쿠버네티스를 쥐락펴락 할 수 있어야 하기 때문에 그에 맞는 권한을 할당해줄 필요가 있다.

    아래 코드를 yaml 파일에 저장해 kubectl apply 하자. 아래 yamlTiller라는 cluster-admin에 연결된 새로운 권한을 생성한다.

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: tiller
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: tiller
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
      - kind: ServiceAccount
        name: tiller
        namespace: kube-system
    

    이제 Tiller를 쿠버네티스 위에 올리면서, 방금 생성한 권한을 부여해 보자.

    helm init --service-account tiller
    

    완전히 Tiller Pod가 준비될 때까지 잠깐 기다린 후, helm version 명령어를 다시 실행해 서버 측에도 완전히 Helm이 준비되었는지 확인하자. 준비가 되었다면 아래와 같은 값이 출력될 것이다.

    필자는 구버전 helm이 설치되어 있는 테스트 환경에서 명령어를 실행해 버전이 v2.9.1로 표시되었다. 글을 작성하는 현재 최신 helmv2.13.0이다.

    $ helm version
    Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
    Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
    

    Helm Chart로 애플리케이션 실행하기

    Helm이 준비되었다면, 이제 Helm Chart가 필요하다. 마치 윈도우 컴퓨터에 설치하는 .exe 패키지처럼, 쿠버네티스라는 컴퓨터를 위한 애플리케이션 패키지를 구해오는 것이다.

    만약 실행하려고 하는 것이 ElasticSearchJenkins 같은 잘 알려진 오픈소스 애플리케이션일 경우, 대부분 해당 제작사에서 Helm Chart를 같이 제작해 배포한다. 이런 Chart들은 Helm Stable Repo 에서 확인할 수 있다.

    Helm 패키지 설치는 helm install 명령어를 통해 이루어진다, 적당한 패키지를 고르지 못했다면, 필자가 만든 데모용 애플리케이션을 설치해보며 어떻게 Helm을 사용할지 감을 잡을 수 있다.

    먼저 이 링크에서 데모 Helm Chart를 다운로드 받은 후, 압축을 풀고, 적당한 텍스트 에디터로 열어보도록 하자. 구조는 아래와 같을 것이다.

    Helm Chart 설치는 tgz로 압축된 상태에서도 가능하지만, 이번에는 실습을 위해 압축을 해제했습니다. 물론 압축 해제된 폴더 그 자체로도 설치가 가능합니다.

    ├── Chart.yaml
    ├── charts
    ├── templates
    │   ├── NOTES.txt
    │   ├── _helpers.tpl
    │   └── deployment.yaml
    └── values.yaml
    

    아래 명령어를 통해 쿠버네티스에 올려보도록 하자.

    쿠버네티스의 모든 동작이 yaml 파일을 기반으로 이루어지는 것처럼, Helm Chart도 결국에는 yaml 파일들의 집합체이다. Helm Chart 설치를 진행하면 templates 폴더 안에 있는 모든 yaml을 실행한다. 예시를 확인하기 위해 deployment.yaml 파일을 열어보자. 내용은 아래와 같을 것이다.

    apiVersion: apps/v1beta2
    kind: Deployment
    metadata:
      name: helm-helloworld
      labels:
        app: helm-helloworld
        chart: helm-helloworld
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: helm-helloworld
      template:
        metadata:
          labels:
            app: helm-helloworld
        spec:
          containers:
            - name: helm-helloworld-container
              image: "alpine:3.6"
              env:
              - name: PRINT_VALUES
                value: 
              command: ["/bin/sh","-c"]
              args: 
              - while true; do echo $PRINT_VALUES; sleep 5; done;
    

    일반적으로 보던 디플로이먼트를 생성하는 yaml 같아 보이지만, 못 보던 무언가가 env 칸에 있다. 여기서 Helm의 진가 중 하나가 들어난다. 바로 파라미터화다. 같은 yaml 파일이여도 동적으로 어떤 값을 넘겨주냐에 따라 다른 결과물을 만들 수 있다. 그리고 그 값들은 Helm Chart 최상위 경로에 있는 values.yaml에 정의된다.

    values.yaml 파일을 열어보면 아래와 같은 값이 먼저 정의되어 있을 것이다.

    printValues: "hello world!"
    

    printValues 값이 hello world! 로 정의되어 있다. 대충 감을 잡으셨겠지만, 이대로 Helm Chart를 쿠버네티스에 설치하면 hello world!를 5초에 한번씩 출력하게 될 것이다. 출력 문구를 바꾸고 싶다면, 이걸 수정하면 된다.

    일단 대충 구조를 파악했으니, 쿠버네티스에 설치부터 해보자. 아래 명령어를 참고하자.

    helm install --name helm-demo --namespace default <압축해제한_HELM_경로> 
    

    우리는 방금 필자가 만든 데모용 Helm Charthelm-demo 라는 설치 이름으로 default 네임스페이스에 설치하였다.

    이제 kubectl get pods 명령어로 방금 실행한 애플리케이션의 Pod 이름을 확인한 후, kubectl logs pod/<확인한_POD_이름> 명령어를 통해 로그를 긁어와보자.

    $ kubectl logs helm-helloworld-8d6f9c5db-84pjv
    hello world!
    hello world!
    hello world!
    hello world!
    hello world!
    

    정상적으로 Pod가 실행되어 로그를 출력하고 있는 것을 확인할 수 있다. kubectl get deployments 명령어로 디플로이먼트도 제대로 생성되었는지 체크하자.

    Helm으로 새로운 애플리케이션을 생성해 봤으니, 이제 업그레이드도 해보자. 하는 김에 출력될 문구를 바꿔봐도 좋겠다.

    helm upgrade helm-helloworld --set printValues="hello helm!" <압축해제한_HELM_경로> 
    

    잠시 기다린다면 새로운 Pod가 새로운 값을 읽고 시작되어, 아래와 같이 hello world! 대신 hello helm! 이라는 문구를 출력할 것이다.

    $ kubectl logs helm-helloworld-8d6f9c5db-5p1bj
    hello helm!
    hello helm!
    hello helm!
    hello helm!
    hello helm!
    

    이처럼 Helm은 애플리케이션 설치와 업그레이드 시 동적으로 값을 바꿀 수 있게 해준다. 이를 잘 응용해 업그레이드 시 도커 이미지의 버전을 바꾸는 등의 사용도 얼마든지 가능하다. 만약 업그레이드를 하는데 이전에 넘긴 값을 그대로 쓰고싶다면 --reuse-values 파라미터를 같이 넘기면 된다.

    자. 작동 되는것도 잘 봤고 적당히 가지고 놀았으니 이제 깔끔하게 정리할 차례다. 현재 설치되어 있는 Helm Chart들은 helm ls 명령어로 확인할 수 있다. 우리가 설치한 Helm Chart의 이름은 helm-helloworld이니 아래 명령어를 통해 완전히 삭제할 수 있다.

    helm del --purge helm-helloworld
    

    완전히 삭제된 후, 다시 helm ls 명령어를 실행해 다시한번 확인해보는 것도 좋다.

    더 알고싶어요!

    방금까지 첫 Helm 사용에 필요한 건 대충 다 해봤다. 이제 본격적으로 배포에 Helm을 사용하고 싶으신 분들은 아래 글들을 참고하면 도움이 될 것이다.

  • eksctl로 구축하는 AWS EKS Kubernetes 클러스터


    이전 글 에서 kubeadm을 사용해 베어메탈 쿠버네티스 클러스터를 구축하는 법을 다루었는데, 아무래도 실 서비스 환경에서는 조금 더 관리할 것이 덜하고 안정적인 무언가가 필요하다.

    그런 생각을 하는 사람은 필자와 우리 독자 뿐만 아니라, 쿠버네티스를 프로덕션에 사용하고 싶어하는 모든 개발자들이 하고 있다. 개발자가 상상한다면 반드시 결과물이 나오는 법. 이미 세상에는 구글, 아마존, MS 등이 제공하는 다양한 관리형 쿠버네티스 서비스들이 나와있다.

    그 중 오늘 우리는 아마존에서 제공하는 AWS EKS를 사용해 클러스터를 구축해볼 것인데, 이게 좀 불편하다. 좀 많이 불편하다. 분명 불굴의 아마존이 제공하는 안정적인 서비스이고, 기존에 익숙하게 사용하던 여러 AWS 서비스들과 연동된다는 점은 참 좋은데, 초기 구축이 타 관리형 쿠버네티스와 비교해 많이 불편하다.

    그래서 등장한 도구가 바로 eksctl이다. 이미 쿠버네티스 네트워크 플러그인인 Weave Net을 선보여 익숙한 분들도 있을 Weaveworks가 제작한 CLI 도구다. EKS 클러스터의 생성과 업그레이드, 삭제까지 모두 간단한 명령어 몇 줄로 해결할 수 있게 해주는 사랑스러운 놈이다.

    아래로 진행하기 전, 사용할 수 있는 AWS 계정과 EC2 / EKS 접근이 가능한 IAM 엑세스 키, 그리고 aws-cli를 설치해두길 바란다. eksctl은 설치되어 있는 aws-cli에 의존해 계정 인증을 하고 작업을 진행한다.

    그래서 언제 써보나요?


    지금부터 쓸꺼다. 바로 지금.

    macOS 기준으로 Homebrew를 사용한다면, 아래 명령어로 쉽게 설치할 수 있다.

    brew tap weaveworks/tap
    brew install weaveworks/tap/eksctl
    

    타 Unix-like 운영체제에서는 아래 명령어로 설치할 수 있다.

    curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
    sudo mv /tmp/eksctl /usr/local/bin
    

    모든 설치가 완료되었다면, 이제 바로 클러스터 하나 뚝딱 만들 수 있다. 아래는 기본적인 파라미터가 포함된 예제 명령어다.

    더 많은 옵션은 eksctl 공식 문서에서 찾아볼 수 있다.

    eksctl create cluster --name=<클러스터_이름> --nodes=<worker_node_갯수> --node-type=<EC2_인스턴스_종류> --region=<AWS_REGION> --kubeconfig=<KUBECONFIG_저장_경로>
    

    꽤나 직관적이다. 이제 한 10여분 기다리면 별다른 함정(?) 없이, 내가 지정한 AWS 리전에 지정한 이름, Worker 갯수, KUBECONFIG까지 깔끔하게 생성해 저장해준다.

    생성이 완료된 클러스터의 KUBECONFIG 파일을 열어보면 아래와 같은 값들이 있을 것이다.

    (...)
    
    current-context: (...)
    kind: Config
    preferences: {}
    users:
    - name: (...)
      user:
        exec:
          apiVersion: client.authentication.k8s.io/v1alpha1
          args:
          - token
          - -i
          - (...)
          command: aws-iam-authenticator
          env: null
        
    

    아래에 aws-iam-authenticator 가 보이는가? AWS EKS 클러스터가 계정 인증 처리를 위해 사용하는 소프트웨어다.

    우리가 쿠버네티스 명령어를 실행하면 바로 저 aws-iam-authenticator가 계정 인증을 마친 후 실제 쿠버네티스 API에 전달될 것이다. eksctl과 마찬가지로, aws-cli에 로그인된 엑세스 키 정보를 사용한다.

    macOS 기준으로 아래처럼 설치하면 된다. 아래 링크가 너무 오래되었거나 타 운영체제를 사용할 경우 이 링크를 참조하면 좋다.

    curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/darwin/amd64/aws-iam-authenticator
    
    chmod +x ./aws-iam-authenticator
    
    cp ./aws-iam-authenticator $HOME/bin/aws-iam-authenticator && export PATH=$HOME/bin:$PATH
    
    echo 'export PATH=$HOME/bin:$PATH' >> ~/.bash_profile
    

    이제 aws-iam-authenticator help를 테스트로 실행해봐 제대로 작동하는지 확인하자. 정상적으로 도움말이 뜬다면 성공.

    aws-cli까지 제대로 로그인 된 것을 확인했다면, 아래 명령어로 KUBECONFIG를 지정한 후, 간단히 클러스터 정보를 받아와보자.

    export KUBECONFIG=<내_KUBECONFIG_파일_경로>
    
    kubectl get node
    

    별다른 계정 오류 등이 발생하지 않고 아래와 같이 내 클러스터의 Worker 노드 정보가 뜬다면 정상적으로 연결된 것이다.

    NAME                      STATUS   ROLES    AGE   VERSION
    (...).compute.internal    Ready    <none>   1d   v1.11.5
    (...).compute.internal   Ready    <none>   1d   v1.11.5
    (...).compute.internal    Ready    <none>   1d   v1.11.5
    

    AWS EKS는 생성 과정만 조금 다를 뿐, 한번 생성되면 일반적인 Kubernetes와 아주 똑같다. 이제 아래 문서들을 참고해 웹 대시보드나 Helm 등을 설치하고 본격적으로 내 워크로드들을 올릴 수 있다.

    클러스터 정보 업그레이드

    AWS EKS에서 사용자가 신경써야 할 것은 Worker가 전부다. Master (API) 는 AWS가 알아서 잘 관리하며, 만약 문제가 있을 경우 사용자 모르게 알아서 고친다. 우리는 Worker 노드만 우리의 워크로드에 맞게 잘 조율해주면 된다.

    EKS의 Worker 노드들은 AWS Cloudformation 에 정의된 Nodegroup에 의해 관리된다. 지금 내 AWS 콘솔의 Cloudformation 에 들어가보면 eksctl이 자동으로 생성한 Nodegroup이 보일 것이다. 이 템플릿이 EC2 Auto Scaling Group도 만들어 알아서 뚝딱 Worker도 올리고, VPC도 만들고, 이것저것 필요한 건 다 한다.

    그러므로 자연스럽게 클러스터 정보를 업그레이드할때도 Nodegroup을 업그레이드해야 얘가 알아서 나머지를 반영하는 구조가 된다. 어려울 것 같지만 eksctl을 사용하면 의외로 쉽게 처리할 수 있다.

    마찬가지로 더 많은 옵션은 eksctl 공식 문서에서 찾아볼 수 있다.

    eksctl create nodegroup --cluster=<클러스터_이름> --region=<AWS_REGION> --nodes=<worker_node_갯수> --node-ami=<EKS_AMI_ID, 혹은 auto> --node-type=<EC2_인스턴스_종류>
    

    이 명령어는 내가 지정한 클러스터에 새로운 설정을 담은 새로운 Nodegroup을 만들어준다. Nodegroup은 곧 자동으로 새로운 Worker들을 생성해 클러스터 붙혀준다. 다른 타입의 Worker들을 만들고 싶거나 쿠버네티스 버전 (AMI) 를 업그레이드 하고 싶을 경우 들에 유용하다. 이전 Nodegroup이 필요가 없어졌다면, 아래 명령어로 삭제하면 된다.

    eksctl delete nodegroup --cluster=<클러스터_이름> --region=<AWS_REGION>
    

    클러스터 삭제하기

    클러스터 잘 가지고 놀았고 이제 치우고 싶을 때, 아래 명령어로 쉽게 삭제할 수 있다.

    eksctl delete cluster --cluster=<클러스터_이름> --region=<AWS_REGION>
    

    끝!

    방금까지 eksctl을 사용해 EKS를 전반적으로 둘러보고 맛까지 보았다. 이제 내 진짜 프로덕션 환경을 생각해 다시 클러스터를 세워, 덜 머리아프게 고가용성 워크로드를 돌려보자. eksctl로 복잡한 쿠버네티스 조금이라도 쉽고 직관적이게 사용하셨으면 좋겠다. 화이팅.

    나는 고급 옵션이 필요해요

    대부분의 경우 위의 명령어로 “범용적인” 클러스터를 만들 수는 있으나, 조금 더 고급 옵션이 필요한 분들은 꼭 계신다. 그런 분들을 위해 몇가지 준비했다. 물론 위에 언급했던 것처럼 공식 문서에서 필요한 것은 다 얻을 수 있지만, 몇가지 정리해봤다. 아래 Flag들은 따로 언급하지 않는 한 클러스터 첫 생성과 Nodegroup 생성 둘 다에 쓰일 수 있다.

    --node-ami=<EKS_AMI_ID, 혹은 auto>
    

    Nodegroup 생성에서 사용하고 싶은 EKS AMI를 지정할 수 있다.

    --ssh-access --ssh-public-key=<내_SSH_PUBLIC_키>.pub
    

    기본적으로 eksctl이 만든 Worker 노드들은 SSH 접속이 막혀있다. 이 명령어를 사용하면 클러스터 생성 시 내가 사용하고 싶은 키를 연결할 수 있다. --ssh-public-key=<내_AWS에_등록된_키> 로 이미 내 EC2 리전에 등록된 SSH 키를 바로 연결도 가능하다.

    --node-volume-size=50
    

    기본적으로 EKS의 Worker 노드 저장공간은 20GB다. 대부분의 경우 실 워크로드에는 EBS 볼륨은 연결해 사용하니 크게 지장은 없지만, 만약 높은 저장공간이 필요한 경우 이 명령어처럼 GB 단위를 직접 기입해 늘릴 수 있다.

    --node-private-networking
    

    Worker 노드들을 Private VPC에 위치시키고 싶은 경우, 이 명령어를 통해 Private VPC를 생성해 해당 Nodegroup의 노드들을 안에 위치시킬 수 있다.

    eksctl create cluster \
      --vpc-private-subnets=subnet-0ff156e0c4a6d300c,subnet-0426fb4a607393184 \
      --vpc-public-subnets=subnet-0153e560b3129a696,subnet-009fa0199ec203c37
    

    이미 만들어둔 VPC를 사용해 클러스터를 생성하고 싶은 경우, 이 명령어처럼 VPC 서브넷 아이디를 직접 지정해 만들 수 있다.

    다른 옵션들이 궁금하다면 위에 걸어둔 링크를 타고 공식 문서를 살펴보자.

  • 스스로 Kubernetes 클러스터 구축하기


    자. 새로운 주제의 새로운 시작이다.

    단순한 흥미 목적이 됐건, 프로덕션 서비스를 꿈꾸고 있던 간에, 모든 일의 시작은 환경 구축이다. 정말 다행인 건, 쿠버네티스가 점점 유명해지고 활발하게 쓰이는 만큼 사용도 편하게 할 수 있도록 다양한 도구와 서비스가 나오고 있다는 점이다. 요즘은 AWS나 GCE같은 퍼블릭 클라우드 사업자에서 원클릭 쿠버네티스 클러스터 서비스도 제공하고 있다.

    그렇지만, 첫 단추부터 잘 꿰어야 한다고 하지 않나. 설령 내 클라우드 사업자가 쿠버네티스 서비스를 제공하지 않더라도, 혹은 온프레미스 환경을 사용해야 한다고 해도 문제업이 쿠버네티스 클러스터를 구축할 수 있도록, 오늘 우리는 kubeadm 이라는 도구를 사용할 것이다.

    본격적인 구축에 앞서…

    kubeadm은 가장 빠르고 간단하게 미니멀한 쿠버네티스 클러스터를 구축할 수 있는 쿠버네티스 공식 인증 도구다. 많은 사람들과 가이드에서도 kubeadm 사용을 권장하고 있으니 혹여나 여기서 다루는 내용이 비표준일 것이라는 걱정은 안 해도 된다.

    필자의 테스트 환경은 아래와 같다.

    - Ubuntu 16.04 1vCore / 1GB - master
    - Ubuntu 16.04 1vCore / 2GB - node1 (slave)
    = Ubuntu 16.04 1vCore / 2GB - node2 (slave)
    

    잠깐. master? node? 생소한 단어가 막 나온다. 아니, 얼핏 개념은 알 것이다. master가 책임자고 node가 일하는 녀석이라고 말이다.

    바로 그거다. 쿠버네티스에서도 크게 달라지는 것은 없다. master에는 쿠버네티스 전체를 제어할 수 있는 API 서버나, 쿠버네티스 클러스터에 관한 정보를 저장하는 etcd 저장소 등이 구동된다. node가 진짜 일꾼이다. 우리가 앞으로 올릴 애플리케이션 컨테이너는 바로 node에서 구동될 것이다. 이 개념을 감안해 본인의 환경에 맞게 적절하게 테스트 환경의 리소스를 조절하길 바란다.

    master 구성하기

    먼저 master에 ssh 접속한 후, 다음 명령어를 통해 필요한 패키지를 설치해보자.

    sudo apt-get update
    sudo apt-get install -y docker.io
    
    apt-get update && apt-get install -y apt-transport-https
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
    
    cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
    deb http://apt.kubernetes.io/ kubernetes-xenial main
    EOF
    
    apt-get update
    apt-get install -y kubelet kubeadm kubectl
    

    자. 방금 우리는 명령어 몇 줄을 통해 깡통 머신에 도커 데몬과 쿠버네티스 클러스터에 필요한 필수 패키지들을 설치했다. 이제 이 녀석을 master로 탈바꿈시켜야 하는데, 그것마져도 간단하다. 다음 한 줄이면 된다.

    kubeadm init --apiserver-advertise-address <master_프라이빗_IP> --apiserver-cert-extra-sans <master_퍼블릭_IP> --pod-network-cidr=10.244.0.0/16
    

    간단하다고는 했는데, 뭐가 좀 많다? 하나하나 짚어보자. --apiserver-advertise-address는 master의 메인 IP 주소. node들이 직접 붙을 바로 그 주소다. 당연히 보안상 프라이빗 네트워크를 사용하는 편이 좋으니, master 서버의 프라이빗 IP를 기입하자. --apiserver-cert-extra-sans는 추가적으로 인증에 사용할 IP 주소. 외부에서 쿠버네티스 클러스터에 접근할 수 있는 편이 관리 측면에서 월등하게 편리하니, master의 퍼블릭 IP를 기입한다.

    --pod-network-cidr 는 조금 다른 녀석인데, 쿠버네티스 클러스터에서 구동되는 모든 구성요소 (컨테이너) 등은 자체적인 오버레이 네트워크를 통해 서로 통신한다. 쿠버네티스가 자체적으로 제공하는 오버레이 네트워크 솔루션은 없고, 서드파티를 사용해야 하는데 그 중 우리가 사용할 것은 가장 대중적으로 사용되는 Flannel 이다. 10.244.0.0/16이 바로 Flannel이 요구하는 CIDR 범위임으로 init시 지정해줘야 추후 사용에 무리가 없다.

    초기 셋업 과정들이 자동으로 진행된 후, 완료되었다는 메시지와 함께 kubadm join 으로 시작하는 명령어가 출력되었을 것이다. 이것을 복사해서 한쪽에 잘 보관해두자. 눈치가 빠른 분들은 알아차렸겠지만 추후 이 명령어를 사용해 node들을 master에 연결시킬 것이다.

    거의 다 왔다. 방금 만든 쿠버네티스 master에 오버레이 네트워크 플러그인만 설치하면 된다. 바로 위에서 다룬 Flannel을 말하는 것이다.

    cp /etc/kubernetes/admin.conf $HOME/
    chown $(id -u):$(id -g) $HOME/admin.conf
    export KUBECONFIG=$HOME/admin.conf
    

    위 과정을 통해 KUBECONFIG 파일을 사용할 수 있도록 준비시킨다. 쿠버네티스 클러스터의 접속 정보가 담긴 일종의 열쇠라고 생각해도 무방하다.

    sysctl net.bridge.bridge-nf-call-iptables=1
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
    

    오버레이 네트워크가 작동할 수 있도록 방화벽을 약간 만져주고, 플러그인을 설치해 보자. 여기에 쓰인 kubectl apply -f 명령어는 앞으로도 자주 쓸 녀석이다. 쿠버네티스의 대부분의 애플리케이션 생성, 기타 구성 과정 등은 yaml 파일에 저장된 구성 정보를 읽어 이루어진다. 방금 우리는 온라인 저장소에서 파일을 가져와 바로 쿠버네티스 클러스터가 읽게 만들었다.

    이제 쿠버네티스의 뿌리가 갖춰졌으니, 이제 간단히 커뮤니케이션을 해보자. 아래 과정을 통해 쿠버네티스 API에서 현재의 클러스터 구성 상태를 불러올 수 있다.

    kubectl get nodes
    

    나의 master 노드와 현재 상태 (Ready) 가 보이는가? 잘 따라오고 있다!

    클러스터에 node 추가하기

    기본 베이스는 master와 다르지 않다. 동일한 Docker 데몬, 동일한 kubelet 등 쿠버네티스 의존성을 요구한다.

    node가 될 서버에서 아래 과정을 통해 필요한 물밑작업을 진행하자.

    sudo apt-get update
    sudo apt-get install -y docker.io
    
    apt-get update && apt-get install -y apt-transport-https
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
    
    cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
    deb http://apt.kubernetes.io/ kubernetes-xenial main
    EOF
    
    apt-get update
    apt-get install -y kubelet kubeadm kubectl
    

    여기까지 따라왔다면 다른 것은 딱 하나, 최초의 master에서는 init 과정을 통해 클러스터를 생성했다면, 이제 node에서는 join 커멘드로 이미 생성한 클러스터에 참여하면 된다.

    위에서 언급한 join 커멘드 복사본을 가져와 node에 붙혀넣기한다. 다음과 같은 형태로 존재한다.

    kubeadm join <MASTER_IP:PORT> --token <TOKEN> --discovery-token-ca-cert-hash sha256:<HASH>
    

    잠시 시간이 지나고, master에서 kubectl get node 커멘드를 실행하면 우리가 추가한 node까지 같이 출력되는 모습을 볼 수 있다. Ready 사인이 들어와 있으면 사용 준비 완료.

    클러스터 시각화하기

    로컬 머신에서 쿠버네티스 클러스터에 접근하고 싶을 경우, 서버에 있는 KUBECONFIG 파일을 옮긴 후 열어 프라이빗 IP가 적혀있는 server 부분을 master의 퍼블릭 IP로 교체해 주어야 합니다. kubectl 설치가 따로 필요할 경우, 이 곳을 참조하세요.

    방금 우리는 사용 가능한 쿠버네티스 클러스터를 완성시켰다! 그래, 다 좋은데, 이제 뭘 해야 할까? 아직 쿠버네티스에 전혀 익숙하지 않은데, 이 검은 창만 보며 모든 일을 진행해야 하는 걸까?

    다행히 아니다. 쿠버네티스는 아래와 같은 멋진 공식 웹 UI를 제공한다. 다만 따로 설치해야 할 뿐. 하지만 쿠버네티스를 처음 사용하는 사람에게는 좋은 실습과 적응 과정이 될 수 있다. 자, 따라오자.


    kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
    

    이제 쿠버네티스 시스템이 알아서 필요한 파일을 다운로드받아 대시보드를 구동시킬 것이다. 위의 kubectl apply -f 명령어는 영어 그대로, kubectl을 통해 file (-f)을 적용시키는 일을 한다. 방금 예시처럼, 앞으로 대부분의 쿠버네티스 리소스 생성은 완성된 yaml 파일을 통해 이루어질 것이다. 일단 파일을 완성만 하면 그 어떤 쿠버네티스 환경에서도 똑같이 구동된다. Infrastructure-as-Code가 피부로 확 체감되는 순간이다.

    얘기는 나중에. 기껏 대시보드를 설치했으니 직접 접속해보자.

    쿠버네티스에서는 대시보드의 접속에 kube-proxy를 사용할 것을 권장한다. 쿠버네티스 API를 통해, 컨테이너 네트워크에 직접 붙어 localhost를 통해 내부 구성요소들에 접속할 수 있게 해주는 컨셉인데, 이를 사용하면 로컬 머신에서의 컨테이너 (혹은 서비스) 접근을 위해 외부 네트워크로 포트를 열지 않아도 된다. 쿠버네티스 대시보드도 마찬가지로 외부에 그냥 오픈할 경우 여러가지 보안 문제가 생길 수 있다. 조금 불편하더라도 프록시를 사용해 접속하도록 하자.

    아래 명령어로 바로 kube-proxy를 구동할 수 있다.

    kubectl proxy (&를 뒤에 붙혀 백그라운드 구동 가능)
    

    별다른 에러가 발생하지 않는다면, 이제 내 로컬 머신이 클러스터 내부 네트워크에 붙었다는 소리다. 웹브라우저에서 아래 주소로 접근하면 대시보드가 반갑게 환영해줄 것이다.

    https://<master-ip>:<apiserver-port>/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
    


    빰. 어렵게 어렵게 만났다. 근데 잠깐만, 로그인을 하라고 한다. kubeconfig 파일 또는 토큰을 입력해야 하는데, 아마 지금 가지고있는 kubeconfig를 넣어도 로그인이 안될 것이다. 파일 안에 토큰 정보가 들어있지 않기 때문이다. 우리는 어드민 권한으로 로그인하고 싶으니, 어드민 권한을 가진 클러스터 내부 계정을 하나 만들어 토큰값을 뽑아보자. 아래의 코드를 긁어 yaml 형태로 저장한 후, 클러스터에 적용하는 것부터 시작하자.

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: dashboard-admin
      namespace: kube-system
    
    ---
    
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: dashboard-admin
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - kind: ServiceAccount
      name: dashboard-admin
      namespace: kube-system
    

    모든 yaml 파일 적용은 조금 전 해봤던 것과 같이, kubectl apply -f <파일_경로> 명령어를 사용하면 된다.

    콘솔에 무언가 만들어졌다고 주르륵 떴는데, 토큰값은 따로 보이지 않는다. 괜찮다, 정상이다. 이제 계정만 만들어졌을 뿐, 토큰은 우리가 뽑아야 한다.

    kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep dashboard-admin | awk '{print $1}')
    

    위 명령어를 통해 토큰값을 얻을 수 있다. 값을 복사한 후 대시보드 로그인 창에 넣어보면 정상적으로 메인 화면이 나오는 것을 볼 수 있다. 일일히 토큰값을 복사하는게 귀찮다면 kubeconfig 파일에 입력할 수도 있는데, 아래의 예시를 따라하자. 파일 형태는 조금 다를 수 있으나 위치는 동일하다.

    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority-data: (...)
        server: (...)
      name: (...)
    contexts:
    - context:
        cluster: (...)
        user:(...)
      name: (...)
    current-context: (...)
    kind: Config
    preferences: {}
    users:
    - name: (...)
      user:
        token:
        <여기에 토큰값>
        exec:
          (...)
    

    정상적으로 입력했다면, 로그인 창에서 kubeconfig 파일을 선택하는 것으로 접근이 가능할 것이다.

    Hello, World?

    방금 전 과정까지 해서 우리는 직접 깡통 머신에 쿠버네티스를 설치하고, 클러스터를 구성하고, 대시보드 애플리케이션 구동과 내부 계정 생성까지 모두 해보았다. 아직은 어벙벙 하겠지만, 앞으로의 쿠버네티스 사용 대부분은 방금 우리가 거쳐온 방법들을 사용한다. 역시 맛보기로는 직접 만들어보는 것처럼 좋은 일이 없다.

    이제 막 클러스터가 만들어졌으니, 무언가 자꾸 올려보고 싶은 건 당연하다. 아래의 링크들을 참조하면 여러가지 데모 애플리케이션을 직접 실행하며 감을 잡을 수 있을 것이다.

    마지막으로 이 글을 정독한 모두에게, 클러스터 오케스트레이션 세상에 첫 발을 내딛을 걸 환영한다고 박수를 쳐주고 싶다. 처음 접근은 어려울 지 몰라도, 한번 익숙해지면 이전의 서버 운영과는 차원이 다른 편안함과 유연함을 맛볼 수 있을 것이라 장담한다.

    그리고 다음에 다룰 내용에 관한 글도 하나 첨부한다. 기존의 쿠버네티스 yaml 파일도 쓸만은 하지만, 너무나 정적인 탓에 같은 애플리케이션 (또는 이미지) 기반으로 여러 환경을 만들어야 할 경우 그 환경들을 위한 모든 yaml 파일을 만들어야 하는 등 단점이 명확한데, Helm 이라는 패키지 매니저가 그런 문제를 해결해줄 수 있다. 자세한 내용은 다음에 다루겠다.

  • 나도 Kubernetes 써보고 싶어요!

    안녕 독자들. 주인장은 아직 살아있다. 마지막 글을 1월에 남기고 쭉 잠수를 탔는데, 그 사이 정말 많은 일이 있었다. 처음으로 한 회사에 들어가 많은 경험을 했지만, 그리 행복하지 않았기도 했고… 이전에는 생각하지도 않았던 여러 요소들에게 스트레스도 많이 받았다. 결국 3개월만에 그 곳을 나오고 다른 곳을 물색하다 우연히 bitHolla라는 암호화폐 관련 기술을 다루는 스타트업에 DevOps 엔지니어로 참여하게 되었다.

    비트홀라는 여러 암호화폐 거래소에 동시에 연결해 빠른 거래를 할 수 있게 해주는 트레이딩 터미널 - XRayTrade와, 직접 암호화폐 거래소를 개설할 수 있게 도와주는 거래소 플랫폼 - HollaEx를 서비스하고 있는 스타트업이에요. 외국인들로 구성된 기업이라 영어로 일할 수 있다는 점, 쓸데없는 규율이 존재하지 않아 마음 편하게 하고싶은 일을 할 수 있다는 점이 너무 마음에 들어 만족하며 일하고 있어요.

    필자가 비트홀라에서 담당하고 있는 일 중, 가장 중요하고 궁극적으로 이루려고 하는 일이 모든 인프라의 쿠버네티스 마이그레이션이다. 기존 인프라는 도커화(dockerize)는 되어 있지만, 모던 아키텍처가 요구하는 컨테이너 오케스트레이션은 이루어지지 않고 있는 상태. 지금의 서비스에는 큰 문제가 없지만, 추후 규모가 커졌을 때의 자유로운 스케일 업 / 다운, 장애 복구, 그리고 빠르고 간편한 코드 배포를 위해 쿠버네티스를 대체 솔루션으로 선택했다.

    물론 필자가 이전에 다뤘던 것 처럼, 도커 네이티브로도 Docker Swarm이라는 컨테이너 오케스트레이션 솔루션이 존재한다. 그렇지만, 최근의 업계 트렌트와 이 둘의 지원하는 기술 차이, 외부 단체의 서포트 정도 등을 봤을 때, 쿠버네티스가 현재 사용할 수 있는 가장 발전되고 미래가 유망한 오케스트레이션 솔루션이라는 결론이 나왔다.

    여러분 모두 쿠버네티스 하세요!!

    잠깐만요. 그래서, 쿠버네티스가 뭔데요?


    쿠버네티스 (또는 줄여서 k8s)는 한 줄로 정리하자면 도커 컨테이너 기반 서비스 그 자체를 쉽게 이룰 수 있게 도와주는 궁극적인 플랫폼 이라고 할 수 있다.

    착각할 수도 있는데, 쿠버네티스와 도커는 별개가 아니다. 쿠버네티스는 도커 데몬과 연결되어 기존에 수동으로 하나하나 설정하던 모든 작업을 쿠버네티스 단에서 처리할 수 있게 해준다. 일종의 도커라는 컴퓨터를 굴리는 운영체제라고 생각하셔도 좋다.

    쿠버네티스를 사용하면 여러 도커 호스트(서버)를 하나의 클러스터로 쉽게 묶어 서비스를 배포할 수 있다. 여기서 어떤 호스트에 얼만큼 컨테이너를 분배할 지 등도 쿠버네티스가 자동으로 결정해준다. 기존 도커 호스트를 따로따로 운영하는 것보다 더 효율적인 자원 분배가 가능하다는 말이다. 물론 어떤 호스트에 어떤 컨테이너가 있는지 따로따로 기억할 필요도 전혀 없어지게 된다. 자체적인 이미지(코드) 배포 기능을 가지고 있어 기존 서비스의 중단 없이 신 버전 코드로 업데이트도 가능하고, 추가적인 외부 저장소(AWS EBS 등)를 쿠버네티스 클러스터 자체와 마운트해 데이터베이스 같은 Stateful한 애플리케이션도 문제없이 운영할 수 있고 말이다. 뿐만 아니라, 내 서비스가 유지해야 할 필수 동작(설정) 선언에 따라 클러스터가 스스로 똑같은 상태를 유지한다. 도커 호스트 일부가 다운되는 등 문제가 발생하더라도, 현재 사용할 수 있는 자원을 파악해 새로운 호스트로 즉시 똑같은 구성의 컨테이너를 생성한다.

    휴, 이제 숨 쉬셔도 됩니다. 어때요. 여기까지만 들어도 사용해보고 싶은 마음이 확 들지 않을까?

    함께 조금만 참자. 앞으로 일종의 시리즈 물처럼 쿠버네티스 클러스터의 구축부터, 현재 도커화해서 사용하던 애플리케이션의 쿠버네티스 레시피화(yaml 파일), Helm 패키지 매니저를 통한 더 쉬운 애플리케이션 배포, Jenkins 등의 CI 도구를 사용하는 애플리케이션 배포 자동화까지 모두 다룰 예정이다. 앞으로의 글만 살펴봐도 즉시 쿠버네티스를 사용할 수 있게 말이다!

    다음 글이 업로드되면 이 글 아래에 링크를 달아 둘 예정이다. 그동안 아래의 문서들을 읽고 있으면 도움이 될 것 같다.

    사실 이번 글부터 말투를 조금 부드럽게 바꿔볼려 했는데, 다시 들여다보니 손발이 오그라들어 일부분 (이라고 쓰고 거의 다) 예전 스타일로 롤백했다. Helm rollback kycfeel.github.io <OLD_RELEASE>

    참고 문서

    다음 글

  • Homebridge로 미지원 IoT 기기 HomeKit 제어하기

    AliExpress에서 몇개월 전 할인에 혹해 충동구매한 Yeelight의 스마트 컬러 LED 전구가 해를 넘어서도 책장 위에서 먼지만 쌓이고 있는 것을 보고, 드디어 사용할 마음을 먹었다. IKEA에서 싸고 이쁜 플로어스탠드 하나를 주문하고 잠깐 생각해보니, 조명의 제어가 걱정되기 시작했다.

    물론 Yeelight 측에서 기본적으로 제공하는 앱을 통해 제어가 가능하지만, 조금 더 힙하고 맛깔나는 방법을 원했다. 마치 Apple의 유튜브 광고에 나오는 이런 것을 말이다. 아쉽게도, 내가 구매한 이 조명은 Apple에게 어떠한 HomeKit 인증도 받지 못했지만, 지금이 어떤 세상인가. Homebridge라는 HomeKit 에뮬레이션 서버가 필자를 구재할 것이니.

    나는 편법이 좋아요

    Homebridge는 Node.js 기반으로 만들어진 홈킷 에뮬레이션 서버다. 다시 말해, Apple HomeKit 액세서리 인증을 받지 못한 IoT 기기라도 이 Homebridge를 통해 HomeKit으로 제어할 수 있다는 소리다. IoT를 좋아하는 친구에게 이전에 잠깐 말은 들어본 적 있지만, 직접 검색해보니 생각보다 정말 다양한 플러그인들이 존재했다. 물론 필자가 사용하려 하는 Yeelight 컬러 전구를 위한 플러그인도 있다. 망설일 게 뭔가. 당장 실천에 옮기자.

    이 글에서는 Yeelight만 예시로 다루지만, 플러그인만 존재한다면 비슷한 과정을 거쳐 얼마든지 다양한 기기를 연결할 수 있다. 필자가 다른 기기들도 가지고 있었다면 다뤄봤을 수도 있겠지만, 안타깝게도 필자의 주머니는 얇다 :(

    필자는 추가적인 자원 소모를 막기 위해, 이미 로컬넷에서 작동하고 있던 라즈베리 파이에 Docker 컨테이너 형태로 Homebridge를 구동했다. 미리 빌드된 이미지가 존재하니, 아래 명령어를 통해 바로 컨테이너를 띄워보자. 네이티브 구동을 원할 경우 위 Homebridge GitHub 링크를 타고 들어가 README를 참고하면 된다.

    라즈베리 파이가 아닌 일반 x86 기기에서 구동 시, 이미지 이름 뒤의 :raspberry-pi만 지우면 된다. 알아서 x86용 :latest 이미지를 받아올 것이다.

    docker run \
      --net=host \
      --name=homebridge \
      -e PUID=1001 -e PGID=1001 \
      -e TZ=Asia/Seoul \
      -v </호스트/연결/경로>:/homebridge \
      oznu/homebridge:raspberry-pi
    

    홈 앱과의 연결을 위해 컨테이너는 호스트 네트워크에 직접 연결시켜 줬다. PUID와 PGID는 기본 Docker 유저, 그룹을 뜻하는 1001, 타임존은 서울로 설정하면 된다. 편리한 Homebridge 설정을 위해 원하는 호스트의 특정 경로를 컨테이너의 /homebridge와 마운트하자.

    컨테이너가 정상적으로 켜졌다면 아래와 같은 QR 코드가 콘솔창에 나타날 것인데, 애플 기기에서 홈 앱을 실행해 액세서리 추가 메뉴에서 이 비슷한 QR코드를 스캔하자.


    Homebridge가 홈 앱에 정상적으로 추가되었다면, 다시 콘솔로 돌아와 Yeelight 플러그인을 설치해야 한다. 다행히 복잡하지는 않고, docker exec homebridge yarn add homebridge-yeelight 한 줄로 직접 컨테이너에 명령을 보내 플러그인을 간단히 설치할 수 있다.

    플러그인도 설치했으니 이제 Yeelight를 정상적으로 인식할 수 있도록, 장비 목록에 추가만 해주면 된다. /homebridge 경로와 마운트했던 호스트 위치로 이동해보자. 이 경로에는 Homebridge 앱의 모든 설정 파일들이 동기화된다. config.json 파일을 열어, 아래와 같이 편집하자. 상단의 브릿지와 관련된 설정은 무시하고, 하단 platforms만 건들면 된다.

        "platforms": [
            {
                "platform" : "yeelight",
                "name" : "yeelight"
            }
        ]
    

    여기까지 하면 다 된 것 같은데, 귀찮은 과정이 하나 더 남아있다. Yeelight가 Homebridge와 통신할 수 있게, Yeelight의 개발자 모드를 켜줘야 한다. 하다하다 이젠 전구의 개발자 모드라니. 직접 타이핑하면서도 뭔가 어색하다.

    Yeelight 앱을 통해 전구와 연결된 스마트폰에서, 하단 설정 메뉴를 누르면 ‘긱 모드’라는 버튼이 하나 보일 것이다. 살짝 밀어 켜주면 된다. 이전 버전에서는 개발자 모드라고 제대로 출력이 되었는데, 나름 센스를 부려 Geek 모드로 개명을 시킨 것 같다. 맞는 말이긴 하다. 전구에서까지 개발자 모드를 키고 있는 사람들이 Geek이 아니고 무엇이겠는가.

    필자의 경우 처음부터 손에 바로 잡히는 거리에 Android 기기가 있어 Android용 Yeelight 앱에서 진행했는데, 해외 포럼에서 iOS용 Yeelight 앱은 긱 모드 버튼이 보이지 않는다는 말도 오가는 것 같다. 진행에 참고하길 바란다.


    여기까지 따라왔으면, 정말 다 끝났다. 전구를 켜둔 상태로 아까 설정을 마친 Homebridge 컨테이너를 재시작하면, 자동으로 Yeelight를 감지해 서로 연결될 것이다. 못 미더우면 콘솔 로그를 들여다보자. 애플 홈 앱에서도 알아서 새로 추가한 전구가 보일 건데, 혹시라도 계속 팝업이 안될 경우 Homebridge를 홈 앱에서 지웠다 다시 추가해보자. 다시 잘 보일 것이다.

    홈에서 지운 후 다시 추가 시도 시 ‘이미 추가된 액세서리입니다.’ 와 같은 메시지가 뜨며 진행이 막힐 수도 있다. 이럴 경우 /homebridge 경로의 accessories 폴더와 persist 폴더를 삭제한 후 다시 Homebridge를 시작해보자. 필자도 이렇게 오류를 해결했다.

    시리야, 불 꺼.



    Yeelight 앱에서와 같이, 홈 앱과 시리를 통해 전원부터 빛 색깔, 밝기까지 모두 컨트롤 가능한 것을 확인할 수 있다. 여기서 혹시 외부 네트워크에서의 기기 원격 제어는 어떻게 하냐 물어본다면, iPad나 Apple TV를 구매하시라고 미리 답을 드린다.

    농담이 아니라, 이 두 기기는 Apple이 직접 권장하는 (그리고 유일한) HomeKit 중계 서버로 동작하며, 여러가지 자동화나 외부 연결도 이 녀석들을 통해야만 가능하다. 배보다 배꼽이 더 커질 것 같다. 아직 필자는 스탠드 조명 하나만 연결되어 있기에 로컬넷 한정 제어로도 만족한다. 여차하면 구형 iPad를 가지고 있으니 활용해볼 수도 있을 것 같고 말이다.

    무엇보다 이제 당당히 외칠 수 있다.

    시리야, 불 꺼.