• 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를 가지고 있으니 활용해볼 수도 있을 것 같고 말이다.

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

    시리야, 불 꺼.

  • Docker Swarm으로 프로덕션 아키텍처 세우기

    2010년대 중반 백엔드 업계는 일종의 ‘클러스터 붐’을 맞았다. Docker를 비롯해 비교적 사용이 간편하며 쉽게 규모를 확장할 수 있는 도구들이 등장하고, AWS나 GCP 등 대표적 클라우드 서비스 제공자들도 비슷한 기능들을 자체적으로 제공하기 시작하면서 전 세계 수많은 기업들이 자신들의 서비스를 클러스터화 시키기 시작했다. 당장 필자도 이전에 Docker가 기본으로 제공하는 Swarm 기능을 통해 간단히 컨테이너를 클러스터화 하는 방법에 대해 다뤄본 적이 있지 않은가.

    그럼, 왜 그럴까? 모바일 기기와 초고속 인터넷의 폭발적인 보급으로 온라인 서비스 접속 수요도 그만큼 높아지고 있는데, 이를 쉽게 해결해줄 도구들이 잔뜩 등장하고 있으니 다들 물 만난 물고기가 된게 가장 표면적인 이유가 아닐까 싶다.

    그런 흐름에 맞춰, 이번 글에서는 점점 더 높은 수요를 안정적으로 감당해야 하는 프로덕션 상황을 위해 로컬 Swarm 클러스터와 외부 퍼블릭 클라우드가 함께 동작하는 하이브리드 아키텍처를 직접 세워보려 한다.

    알맞은 도구의 선택?


    혹시 이 글을 읽기 전 Docker를 이용한 클러스터화, 더 나아가 서비스 인프라의 오케스트레이션을 위해 사용할 수 있는 도구들을 미리 알아본 적 있다면 백이면 백 그 중 어떤 것을 골라야 잘 골랐다고 소문이 날지 고민하고 있을 것이다.

    대표적으로 Google의 Kubernetes와 Docker에서 자체적으로 제공하는 Swarm 두 개가 도마 위에 오를 것 같은데, Swarm은 Docker에서 아무것도 추가 설치하지 않아도 기본적으로 제공한다는 누구도 이길 수 없는 막강한 장점이 있다. 이는 관리 명령어나 서비스 구조 등도 단일 Docker 머신과 크게 다르지 않다는 뜻이 되기도 한다.

    사실 Kubernetes가 이것저것 지원하는 것도 많고, 실제 사용하고 있는 기업도 더 많지만 한정된 시간과 자원 안에 비슷한 결과물을 만들기에는 Swarm이 최고라 생각한다. 당연히 Swarm도 나름 프로덕션급 오케스트레이션 도구임을 표방하고 있고, 점점 사용자도 늘어나고 있어 세팅의 간편함을 제외하더라도 딱히 어딘가 떨어지거나 하지 않는다. 우리 모두의 행복한 삽질을 위해, Swarm으로 밀고 나가보자.

    Swarm 클러스터 구성

    위에서 침이 마르도록 칭찬했지만, Swarm 클러스터 구성은 입에서 Easy Peasy Lemon Squeezy가 튀어나올 정도로 쉽고 편하다.

    아래가 필자의 테스트 셋업인데, 본인의 상황에 맞게 적당히 응용하면 된다.

    빠르고 편한 세팅을 위해 Subicura 님의 미리 빌드된 Vagrant 이미지를 활용했다. Swarm 클러스터 구성 방법 자체는 필자의 이전 글을 참조 바란다.


    core-01 은 Manager, 나머지 core-02core-03은 Worker 노드다. 프로덕션 상황을 감안하여 웹 서버와 DB가 함께 구동되는 WordPress를 테스트 애플리케이션으로 사용하고, 추가로 원활한 서비스를 위한 traefik 리버스 프록시와 관리 편의를 고려해 Portainer까지 같이 구동한다. 만약 본인의 팀 / 회사에서 구동 예정인 애플리케이션이 따로 존재할 경우, 중간 과정을 대체하거나 따로 수정해도 무방하다.

    사전 작업

    원하는 애플리케이션을 구동하기 전에, 위에 잠깐 언급한 리버스 프록시와 편의장치 먼저 세팅하는 편이 좋다. 특히 리버스 프록시의 경우 미리 설정하지 않으면 애플리케이션을 구동해도 외부와 통신할 통로 마련이 안되니, 당연하기도 하지만 말이다.


    Swarm 환경이 제대로 구축되었다면, Manager 노드에서 아래 명령을 통해 Portainer를 구동하자.

    Portainer에 관련된 자세한 정보는 공식 홈페이지와 필자의 이전 글을 참고하면 된다.

    docker service create \
    --name portainer \
    --publish 9000:9000 \
    --replicas=1 \
    --constraint 'node.role == manager' \
    --mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
    --mount type=bind,src=//opt/portainer,dst=/data \
    portainer/portainer \
    -H unix:///var/run/docker.sock
    

    여기서 주의할 점이, Portainer는 무조껀 Manager 노드에서만 구동해야 한다는 점이다. 명령어를 읽어보면 알겠지만, 작동에 Docker 데몬과의 연결이 필요하다. Swarm에서의 Worker 노드는 말 그대로의 Slave일 뿐, 서비스나 클러스터의 제어 작업 등은 불가하니 이런 서비스의 경우 애초에 실행 자체가 막혀버린다.

    이후 웹 브라우저를 통해 9000 포트로 접속하면 Portainer의 웹 콘솔 화면이 나온다. 물론 애플리케이션 구동에 필수는 아니지만, 전체 클러스터 구성 상태 확인이나 실행중인 서비스 제어 등 CLI보다 편리한 인프라 관리가 가능해지니 애용하면 삶이 조금 더 편해지지 않을까.


    다음은 traefik이다. 물론 더 유명하고 당장 사용할 수 있는 리버스 프록시들은 많이 존재하지만, traefik은 가볍고 컨테이너 환경에 최적화된 힙스터같은 녀석이라 이번 기회에 손을 벌려봤다. 실제로 프로덕션 환경에서도 잘 사용되는 소프트웨어니, 크게 걱정하지는 않아도 된다. 물론 모험 없이 nginx 등을 사용해도 무방할 것 같다.

    아래 명령을 통해 traefik을 구동해보자. 마찬가지로 traefik도 Docker 데몬과의 연결을 필요로 하기에, Manager 노드에서만 구동된다.

     docker service create \
        --name traefik \
        --constraint=node.role==manager \
        --publish 80:80 --publish 8080:8080 \
        --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
        --network traefik-net \
        traefik \
        --docker \
        --docker.swarmmode \
        --docker.domain=traefik \
        --docker.watch \
        --web
    

    명령어를 자세히 들여다보면 traefik-net 이라는 새로운 네트워크를 생성하는 것을 알 수 있다. 이는 기존의 ingress 네트워크와는 별도로, 구동할 애플리케이션이 리버스 프록시를 거쳐 외부와 통신하게 해줄 독립 네트워크다. 추후 애플리케이션 구동 시 따로 네트워크를 traefik-net으로 잡아줄 것이니, 미리 알고 넘어가자.

    각설하고, 웹 브라우저의 8080포트로 접속하면 아래와 같은 웹 콘솔에 접근할 수 있다. 애플리케이션을 구동하면 Providers 메뉴에 관련 정보가 표시되고, Health 메뉴에서 HTTP 상태 코드나 평균 응답 시간이 예쁜 그래프를 입고 나타날 것이다.


    잠깐 다음으로 넘어가기 전에, 우리 traefik이 미친 쥐인지, 애완용 햄스터인지 확인 한번 하고 넘어가면 정신건강에 좋을 것 같은데 말이다. traefik 메뉴얼에서 직접 권장하는 테스트용 웹 서비스인 whoami를 통해 접속 테스트를 진행하자. 아래 명령어를 사용하면 된다.

    docker service create \
        --name whoami0 \
        --label traefik.port=80 \
        --label traefik.frontend.rule="Host:<Manager_노드의_IP주소>"
        --network traefik-net \
        emilevauge/whoami"
    


    다시 traefik 콘솔을 살펴보자. Providers 메뉴에 방금 실행한 whoami0 서비스가 나타났을 것이다. 웹 브라우저로 80 포트에 접속할 경우 정상적으로 whoami0 서비스까지 닿을 수 있다.


    다행히 애완용 햄스터였다 :)

    데이터 보존에 관하여

    이제야 원하는 애플리케이션을 구동하는 차례인가! 하면 아쉽게도 아직 아니다. 중요한 일이 조금 더 남았다. 많은 애플리케이션은 데이터를 저장할 DB, 그리고 기타 쌓이는 자료를 위한 별도의 저장공간을 요구한다. 이런 녀석들을 Stateful 애플리케이션 이라고도 하는 것 같던데, 컨테이너 기술은 별도 기록 / 의존 데이터가 필요없는 Stateless 애플리케이션을 우선적으로 고려해 디자인되었다. 물론 Docker가 제공하는 로컬 볼륨 기능이나, 컨테이너 내부 RW 공간이 존재는 하지만, 이 방법으로는 Swarm 상태에서 다른 컨테이너와 데이터 공유가 불가하고, 특히 내부 RW 공간을 사용했을 경우 기존 컨테이너를 삭제할 시 데이터까지 그대로 소멸되어 버린다는 치명적인 단점이 존재한다.

    이러한 문제는 Swarm이 등장한 초창기부터 지금까지 끊임없이 논의되고 있고, 사용자가 Swarm의 여러 장점들을 모두 포기하더라도 Kubernetes로 넘어가는 가장 큰 이유가 되기도 하는데(Kubernetes의 경우 자체적인 저장공간 오케스트레이션을 지원한다), 다행히 CephGluster같은 분산 파일 시스템을 마운트해 사용하거나, Flocker, REX-Ray같은 Docker 볼륨 드라이버 / 플러그인이 개발되는 등 다양한 해결책이 마련되어 있다.

    이번과 같은 테스트, 또는 소규모 환경에서 Ceph 등을 사용하는 것은 배보다 배꼽이 더 큰 행위라 생각해 제외하고, Docker 플러그인 형태로 제공되는 REX-Ray와 AWS의 S3, RDS 서비스를 이용해 어느 컨테이너에서나 접근할 수 있는 저장 공간, 그리고 DB를 구현하려 한다.

    사실 Flocker의 경우 공유 볼륨을 위한 별도 서버가 필요 없다는 장점 때문에 가장 먼저 사용해보려 했으나, 이를 개발한 ClusterHQ 팀이 최근에 셧다운되어 대부분의 자료가 사라지는 바람에 더 접근이 용의한 REX-Ray를 선택했다. 다행히 팀은 셧다운됬어도 Flocker의 개발은 계속 이어간다는 것 같으니 조만간 따로 사용해본 후 글을 남기도록 하겠다.

    가장 먼저, 우리의 Swarm 시스템이 AWS 자원과 통신할 수 있도록 API 키를 발급받아야 한다. AWS는 IAM이라는 접속인증 관리 서비스를 제공한다. 당장 우리가 필요한 것은 S3 저장소의 접근이니, 별도 사용자 추가를 눌러 AmazonS3FullAccess 권한을 먹여주면 된다. 물론 모든 서비스 접근이 가능한 root 키도 존재하지만, 보안을 생각해 사용하지 않는다.

    계정 생성 후 나오는 엑세스 키는 잘 모셔두고, 이제 Swarm 시스템에 플러그인을 설치해 보자. REX-Ray는 여러 퍼블릭 파일 시스템에 연결할 수 있게 해주는 다양한 플러그인들을 제공하는데, 그 중 우리는 s3fs 플러그인을 사용할 것이다. 이름 그대로, AWS가 제공하는 가장 간단한 형태의 저장공간 S3를 서버에서 파일 시스템(fs)으로도 사용할 수 있게 해주는 녀석이다.

    Master 노드에 접속하고, 아래 명령어로 플러그인을 설치하자.

    docker plugin install rexray/s3fs \
    S3FS_ACCESSKEY=<엑세스_키> \
    S3FS_SECRETKEY=<시크릿_키> \
    --grant-all-permissions=true
    


    이제 AWS S3와 내 Swarm 시스템이 연결되었다. 만약 이전에 사용하던 S3 버킷이 있을 경우, docker volume ls 명령어를 통해 내 모든 버킷을 확인할 수 있을 것이다. 설령 그렇다고 해도 이미 사용중인 버킷을 덮어쓸 수는 없으니, 우리 Swarm만을 위한 새로운 버킷을 하나 만들어 보자.

    AWS의 S3 웹 콘솔에 들어가면, 클릭 몇 번으로 간단히 버킷을 생성할 수 있다. 버킷 이름이나 기타 속성 등을 지정해준 후, 다시 Master 노드로 돌아오자. docker volume ls 명령어를 입력해 방금 생성한 버킷이 제대로 보이는지 확인했다면, 이제 DB를 생성할 차례다.


    마찬가지로 AWS 웹 콘솔의 RDS 메뉴로 들어가면, MySQL을 필두로 하는 다양한 관계형 DB 인스턴스를 생성할 수 있다. MariaDB 또는 MySQL 중 취향에 맞는 것을 선택하고, DB 식별 이름과 계정 등을 설정해주면 된다. AWS에서 처음 DB를 생성하는 경우 약간의 보안 정책과 한글 인코딩 정책을 손봐줘야 하는데, 깔끔하게 정리된 이 포스트를 참조하면 좋을 것 같다. 필자도 도움을 많이 받았다. 이후 생성된 DB의 세부정보를 확인하면 엔드포인트 URI가 적혀있는데, 모니터 한쪽에 잘 띄워두도록 하자. 곧 쓸 꺼다.

    이제 모든 준비가 끝났다. 정말로 애플리케이션을 실행해 보자. 아래 명령어를 적당히 수정해 콘솔에 넣으면 된다.

    docker service create \
    --name wordpress \
    --mount type=volume,source=<S3_버킷_이름>,target=/var/www/html \
    -e WORDPRESS_DB_HOST=<RDS_엔드포인트_URI>:3306 \
    -e WORDPRESS_DB_NAME=<RDS_식별_이름> \
    -e WORDPRESS_DB_USER=<RDS_DB_유저명> \
    -e WORDPRESS_DB_PASSWORD=<RDS_DB_비밀번호> \
    -e WORDPRESS_TABLE_PREFIX=wp_ \
    --label traefik.frontend.rule="Host:<접속에_사용할_URL>" \
    --label traefik.port=80 \
    --network traefik-net \
    --constraint=node.role==worker \
    --replicas 2 \
    wordpress
    

    하나하나 천천히 살펴보자. S3 버킷을 WordPress 서비스의 기본 데이터 경로인 /var/www/html과 연결하고, DB 호스트와 이름을 조금 전 RDS에서 생성한 그것으로 설정했다. --label 태그를 통해 traefik을 거쳐 우리 웹 서비스에 접속에 사용할 URL을 설정하고(테스트 환경에서는 Master 노드의 IP주소로 설정해도 무방), 80 포트를 허용했다. 통신할 네트워크도 물론 traefik-net으로 고정해줬다. 컨테이너가 Worker 노드에서만 구동될 수 있도록 규칙을 잡고, 기본적으로 2개의 컨테이너가 작동하도록 해두었다. 이미지는 최신 버전의 공식 wordpress 이미지를 사용한다.

    더 이상 기다릴 건 없다. 웹 브라우저를 키고 80 포트로 접속하자. WordPress 설치 화면이 나온다면, 우린 모든 역경을 이겨냈다는 뜻이다. 이제 당신의 애플리케이션도 훌륭한 퍼포먼스와 높은 안정성을 자랑하게 되었다.

    마지막으로 /var/www/html의 데이터가 정상적으로 S3 버킷에 저장되는지, DB의 접속은 제대로 되는지, 일부 노드가 다운되도 정상적인 서비스 접속이 가능한지 등 필수 기능 체크는 꼭 거치길 바란다.

    뭔가 아쉬운데…

    필자의 다른 글을 살펴봤다면 알겠지만, 휴대전화 기지국도 직접 만들 정도로 외부 의존성을 가능하면 줄이려고 하는 편인데, 이번에는 투자하는 시간과 노력 대비 결과물을 생각해 사용이 간편한 AWS로 데이터 저장 파트를 대체했다. 의도하지는 않았지만 독자가 원할 경우 컴퓨팅까지 AWS EC2로 대체하는 과정이 좀 더 편해졌을 수도 있겠다.

    그래도 뭔가 아쉬운 느낌이 든다. 아직 보충할 일거리가 조금 더 남았지 않을까. 애플리케이션의 SSL 통신이나 외부 클라우드 의존 없는 100% 로컬 아키텍처 대체법 등이 될 것 같은데, 추후 별도의 글로 작성할 생각이다. 글이 업로드되면 이곳에도 링크를 달아 두겠다.