KOPS on aws

Kubernetes 는 메이저 클라우드 벤더에서 공통적으로 제공하는 서비스가 되었다. Kubernetes cluster 를 생성하고 상황에 맞게 변경하는 등의 관리적인 활동의 도구로서 kops 를 사용하는 것을 고려할 필요가 있다. kops 는 aws 에 잘 동작하도록 지원받고 있으며 aws 의 eks (elastic kubernetes service)와 같은 관리형 서비스를 사용하는 비용이 부담될 때에 도입해 볼 수 있다. eks는 $0.20/hr ($144/month)
이므로 개발 및 테스트 환경에서는 kops 와 같은 오픈 솔루션들이 해결책이 될 수 있다.

단점으로는 kubernetes 버전보다 업그레이드 속도가 늦어서 kops에 의해 생성된 kubernetes 구성 요소들의 버전이 최신 버전이 아니라는 것을 염두에 두어야 한다. 마찬가지로 terraform 같은 솔루션과 연계하려면 호환 버전을 생각해서 설치해야 한다.

terraform 사용을 위해서 tf 파일을 제공한다. terraform, cloudformation 에 익숙한 담당자라면 이런 기능을 활용하는 것도 좋겠다. 요즘은 인프라의 구성을 코드를 통해서 관리하는 것이 사람에 의한 실수를 방지하는 방법이 되고 형상관리의 도움으로 변경에 대한 대처도 가능하다.

HA 구성에 대한 걱정도 있을텐데 이를 위해 멀티 AZ (availability zones) 에 ec2 를 중복 배치하도록 AZ 별로 master 1대 worker 2대로 구성 한다. 한쪽 zone 이 다운되어도 다른 zone 에서 서비스 할 수 있게 하는데 master 나 worker 가 죽으면 auto scaling 방식에 의해 다른 ec2 를 생성해서 서비스를 대체한다. kops 는 kubernetes 의 scale 속성을 aws의 autoscale 방식을 이용해서 지원하고 있다.

Preparation

aws 를 사용하기 위해서 aws client 를 설치하고 aws 명령으로 클라우드의 각종 자원을 다룰 수 있다. 그리고 aws 에 계정이 있어야 kops-cli 로 cluster 를 생성할 수 있다. kops 는 aws 의 기능을 사용하므로 필요한 권한을 계정에 부여하고 있어야 한다. 필요한 권한은 아래와 같다.

  • AmazonEC2FullAccess
  • AmazonRoute53FullAccess
  • AmazonS3FullAccess
  • IAMFullAccess
  • AmazonVPCFullAccess

Install aws-cli

aws cli 는 python 프로그램이다. 따라서 아래와 같이 python 을 설치해야 한다.

sudo apt-get install python2-pip
sudo apt-get install python3-pip
sudo pip install awscli
sudo pip3 install awscli

python 2 버전을 선호 한다면 python2 로 이름을 바꿔서 명령을 실행하면 된다. Redhat 계열의 서버에서는 apt-get 명령 대신에 yum 명령으로 대체해서 실행한다. 만일 다양한 버전의 python 환경이라면 anaconda 를 사용하는 것을 권장한다. window 나 mac 환경에서는 활용하세요.

$ conda create -n aws python=3.7
$ conda activate aws
(aws) $ python --version
Python 3.7.3
(aws) $ pip3 install awscli

windows 경우에는 굳이 별도 설치를 원하면 설치가이드 를 참고해서 설치한다.

아래 명령으로 설치 여부를 확인한다.

$ aws --version
aws-cli/1.16.184 Python/3.7.3 Darwin/18.6.0 botocore/1.12.174

Create Account

aws 사이트 에 가서 계정을 생성한다. free tier 가 있지만 kubernetes 가 정상적으로 동작하려면 t2.small 이상의 규모가 필요하므로 t2.micro 에만 제공되는 free tier 는 사용할 수 없다. 학습 비용으로 생각하거나 회사 계정이 있다면 관리자를 잘 설득하자.

일단 계정의 아이디와 비번을 받아 사이트에 로그인 하고 IAM 서비스 콘솔로 이동해서 왼쪽의 사용자 메뉴를 들어간다. 검색 항목에 자신의 계정을 검색하고 계정을 클릭하여 상세 화면으로 가면 보안자격증명 탭 화면에서 액세스키 만들기를 클릭한다. 만들어진 액세스키와 비밀키를 아래 명령으로 현재 컴퓨터에 등록한다.

$ aws configure
AWS Access Key ID [None]: AKIAQU**********BXCC
AWS Secret Access Key [None]: 7Ca8btFMu********1KpnguH
Default region name [ap-northeast-2]: 
Default output format [json]: 

이 정보는 사용자 홈 디렉토리의 .aws/credentials 에 저장된다. aws 명령을 사용할 때 이용되는 사용자의 계정이고 이 계정에 부여된 권한으로 aws 에 접근하게 된다.

Create Domain

Route53 콘솔로 이동해서 kubernetes 가 동작할 domain 을 생성한다. 공개 domain 으로 하면 실제 외부로 오픈 되므로 주의해야 하고 비용에 대한 고려도 필요하다. 사설 domain 타입으로 생성하면 클라우드 안의 서버들에서만 주소가 공유되고 비용도 들지 않기 때문에 테스트 용으로 적합하다. 단, 개발 컴퓨터등 클라우드 외부에서 이용할 경우 kubernetes 에서 생성된 서비스들의 주소를 컴퓨터 로컬 hosts 파일에 등록해야 하는 수고가 필요하다.

aws route53 create-hosted-zone --name test4kube.com \
--caller-reference dev-kube-20190701 \
--vpc "VPCRegion=ap-northeast-2,VPCId=vpc-8f****e6" \
--hosted-zone-config "Comment=Kube cluster domain for test,PrivateZone=true"

Install kops and kubectl

Install kops

최신 버전의 kops client 를 github 에서 아래와 같이 다운 받고 실행 폴더에 옮겨서 바로 사용할 수 있도록 한다.

$ KOPS_VERSION=$(curl -s \
https://api.github.com/repos/kubernetes/kops/releases/latest \
| grep tag_name | cut -d '"' -f 4)
$ curl -Lo kops "https://github.com/kubernetes/kops/releases/\
download/$KOPS_VERSION/kops-linux-amd64"
$ chmod +x ./kops
$ sudo mv ./kops /usr/local/bin/

mac 에서는 아래 명령으로 설치한다. 설치하면서 필요한 kubectl 까지 설치가 되므로 다음에 나올 kubectl 설치는 생략하자.

brew update && brew install kops

window 에서는 release 에서 다운 받아서 kops-windows-amd64 파일을 kops.exe 로 파일명을 바꾸고 path 변수에 정의된 실행 파일 폴더에 옮겨둔다.

Install kubectl

kubenetes 를 사용하기 위한 client 도구로 kubectl 명령을 사용한다. install_kubectl.sh 파일을 만들어 아래와 같은 코딩을 넣고 저장한다. mac 에서 brew 명령으로 kops 를 설치했다면 이미 kubectl 이 설치되어 있어 이 항목은 넘어가도 된다.

KUBECTL_VERSION=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
 
curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

현재 설치해서 테스트한 버전은 아래와 같다.

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.0", 
GitCommit:"e8462b5b5dc2584fdcd18e6bcfe9f1e4d970a529", GitTreeState:"clean", 
BuildDate:"2019-06-20T04:49:16Z", GoVersion:"go1.12.6", Compiler:"gc", 
Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"12", 
GitVersion:"v1.12.8", GitCommit:"a89f8c11a5f4f132503edbc4918c98518fd504e3", 
GitTreeState:"clean", BuildDate:"2019-04-23T04:41:47Z", GoVersion:"go1.10.8", 
Compiler:"gc", Platform:"linux/amd64"}

Create kubernetes cluster

kops 를 이용하여 aws 에 각종 서비스를 운영할 수 있는 cluster 를 생성한다. kops 는 클라우드 업체에서 제공하는 기능을 활용하여 kubernetes 의 고유 동작들을 지원할 수 있도록 고안되어있다. –cloud 옵션에서 gce, aws, vsphere, openstack 를 선택할 수 있다. 이 문서는 aws 의 활용을 설명하고 있어 aws 에 대한 옵션들 중심으로 설명한다.

Parameters

S3 bucket

클러스터 생성에 필요한 설정들을 보관할 저장소가 필요하다. aws 의 s3 저장소를 이용한다. s3 를 지정하는 방법은 –state 옵션에서 정할 수 있으나 매번 클러스터의 변경이 있을 때마다 지정하는 것이 불편하므로 KOPS_STATE_STORE 환경변수에 정의하는 것을 권장한다. 속성 중에 버전 관리 여부를 활성화 하면 변경 이력을 관리할 수 있어서 이전 구성으로 복귀 가능하게 된다. 버킷명은 클러스터명을 포함할 수 있는 도메인명으로 정의하는 것이 관리가 편하다. 해당 버킷 안에 클러스터 명에 해당하는 폴더가 생기고 그 안에 정보들이 저장된다. 클러스터명이 k8s.test4kube.com 이면 test4kube.com 으로 만들면 되겠다.

export KOPS_STATE_STORE=s3://test4kube.com

Domain

kubernetes 에서 관리되는 서비스들이 외부에 노출되기 위해 dns 명이 필요하다. 이미 위에서 route53 서비스를 이용하여 도메인을 생성하는 것을 설명하였다. --dns-zone 옵션에 생성한 도메인명을 정해준다.

--dns-zone test4kube.com

도메인을 public 으로 생성하지 않은 경우 --dns private 옵션이 필요하다. 기본이 public 으로 인식하기 때문에 지정하지 않으면 클러스터 생성이 실패하게 된다.

aws 에는 AZ 가 있어서 지리적인 사고에 의해 서비스가 중단되지 않도록 여러 지역에서 서비스를 하고 있다. --zones 옵션은 클러스터를 어느 AZ 에서 구성할 것인지 결정할 수 있는데 2개 이상의 zone 을 지정해서 장애에 대비할 수 있다.

--zones "ap-northeast-2a,ap-northeast-2b"

Bastion

bastion 옵션은 보안에 매우 유용하다. 클러스터 생성을 마치면 master, node 가상 서버들이 생성이 되는데 외부에 해커들이 쉽게 찾아내고 침투를 시도하려 한다. bastion 을 두면 각 서버들은 외부와 차단되고 bastion 을 통해서 인증서를 기반으로 안전한 통신을 하게 된다. 이를 위해 아래와 같은 옵션을 설정해야 한다.

--bastion
--networking calico
--topology private

Security

kubernetes 클러스터 내에서 사용하는 인증서가 필요하다. 이 인증서를 기반으로 각 api가 호출되고 각 서비스의 신뢰 구간이 보장되어진다. 아래와 같이 ssh-keygen 명령으로 인증서를 생성한다. 생성 시에 passphrase 를 지정해서 시도하였는데 실패하였고 없이 구성하는 것이 정상적으로 동작하였다. 원인은 따로 찾아봐야겠다. 생성된 인증서는 개인키와 공개키의 한 쌍이 만들어지는데 클러스터 생성에는 공개키 파일(id_rsa.pub)을 사용할 것이다.

ssh-keygen -f ~/.ssh/id_rsa

그 외에 kubernetes 의 기능들은 권한으로 관리된다. --authorization 옵션으로 권한 관리 여부를 설정하는데 기본 값은 RBAC 이고 이것은 클러스터 내에 관리는 되는 서비스들은 계정을 가지며 클러스터 내의 자원들을 이용하는데 필요한 권한을 부여받아 동작하게 된다. 이런 권한 관리 없이 제한 없이 구성하고 싶다면 AlwaysAllow 로 지정하면 된다.

Terraform

--target=terraform 을 사용하면 kops 가 직접 클러스터를 생성하지 않고 terraform 이 처리할 수 있도록 구성 파일을 만들어 준다. 파일 이름은 --out=k8s_terraform 옵션으로 정의한다. 이 옵션으로 실행하면 k8s_terraform 폴더가 생기며 그 안에 terraform 이 필요한 파일들이 생성된다. 아래와 같이 terraform 명령으로 클러스터를 생성할 수 있다.

cd k8s_terraform
terraform plan
terraform apply

현재 테스트한 버전은 아래와 같다.

$ terraform --version
Terraform v0.11.14
$ kops version
Version 1.12.1 (git-e1c317f9c)

VPC

기존에 존재하는 VPC 에 cluster 를 구성하려면 --vpc vpc-8f****e6 처럼 vpc 의 id를 지정하고 해당 vpc 가 어떤 네트워크 범위를 가지는지를 --network-cidr 10.252.224.0/19 처럼 알려주어야 한다. 이 두 옵션을 지정하지 않으면 새로운 vpc 를 만들고 그 안에 cluster 를 구성한다.

기존 vpc 의 경우 이미 생성된 subnet 이 있어서 kops 에 의해 kubernetes 에 필요한 subnet이 생성되면서 충돌이 있을 수 있어서 새로 만드는 것을 권장한다.

Run

위의 조건을 종합해서 아래 명령으로 cluster 생성한다. 마지막의 --yes 옵션이 없으면 각 조건을 점검만 할 뿐 실제로 실행하지는 않는다. –target 옵션으로 terraform 이나 cloudformation 파일 생성만 할 수 있다. 생성된 파일로 이후에 terraform 등을 이용하여 클러스터 생성을 실행할 수 있다.

KOPS_CLUSTER_NAME="k8s.test4kube.com"
KOPS_CLUSTER_ZONES="ap-northeast-2a"
KOPS_MASTER_SIZE="t2.medium"
KOPS_MASTER_COUNT=1
KOPS_NODE_SIZE="t2.small"
KOPS_NODE_COUNT=2
KOPS_TOPOLOGY="private"
KOPS_DNS_ZONE="test4kube.com"
export KOPS_STATE_STORE="s3://${KOPS_DNS_ZONE}"

kops create cluster \
    --name $KOPS_CLUSTER_NAME \
    --state $KOPS_STATE_STORE \
    --zones $KOPS_CLUSTER_ZONES \
    --master-size $KOPS_MASTER_SIZE \
    --master-count $KOPS_MASTER_COUNT \
    --node-size $KOPS_NODE_SIZE \
    --node-count $KOPS_NODE_COUNT \
    --dns-zone $KOPS_DNS_ZONE \
    --dns private \
    --topology $KOPS_TOPOLOGY \
    --bastion \
    --networking calico \
    --ssh-public-key=~/.ssh/id_rsa.pub \
    --yes

위의 명령으로 생성된 아키텍처는 아래 예제와 같이 구성된다. 새로운 vpc 가 생성이 되고 그 안에 2개의 subnet 이 포함이 되는데 하나는 bastion 서버가 상주하고 있어 public 으로 구성되어 있고 나머지 서비스가 배포되고 동작되는 private subnet 에는 master 1대 node 2대 서버가 생성되어 있다.

$ kubectl get nodes
NAME                                               STATUS   ROLES    AGE   VERSION
ip-172-20-35-228.ap-northeast-2.compute.internal   Ready    master   21d   v1.12.8
ip-172-20-42-98.ap-northeast-2.compute.internal    Ready    node     21d   v1.12.8
ip-172-20-47-219.ap-northeast-2.compute.internal   Ready    node     21d   v1.12.8
kubernetes cluster architecture

여기서는 고 가용성에 대한 고려는 하지 않았다. 실제 운영 서비스를 구성한다고 하면 zone 은 2개 이상으로 잡아야 하고 master 서버의 갯수도 2개 이상으로 잡아야 한다. 그리고 master 와 node 서버의 크기도 최소로 잡았는데 실제 서비스의 규모에 따라 aws 의 적절한 서버 타입을 결정해야 한다.

Access through the bastion

Bastion 서버에 로그인 하고 다시 master, node 에 로그인 하는 것은 번거롭다. Bastion 서버를 proxy 로 사용해서 직접 master 와 node 서버를 접근할 수 있다. 아래와 같이 ssh 설정을 하므로 해결할 수 있다. .ssh 폴더 안에 config 파일을 아래 내용으로 생성한다.

Host k8s.bastion
        HostName bastion-k8s-test4kube-co--***********.ap-northeast-2.elb.amazonaws.com
        User admin
        IdentityFile ~/.ssh/id_rsa

Host ip-172-20-*
        User admin
        ProxyCommand ssh -q -W %h:%p k8s.bastion
        IdentityFile ~/.ssh/id_rsa

클러스터 내의 서버들은 admin 계정을 가지고 있고 클러스터 생성시, 사용한 인증키를 가지고 로그인이 가능하다. ProxyCommand 설정에 bastion 서버를 지정하면 그 서버들에 접근할 때 bastion 서버를 통과해서 접근하게 된다.

반면에 HostName 에 지정된 이름은 bastion 서버 이름이 아니고 이를 외부에 노출할 수 있도록 지정된 ELB 의 주소가 적혀있다. 아래 명령으로 클러스터 내의 서버에 admin 계정으로 바로 로그인이 된다.

$ ssh ip-172-20-42-98
...
Are you sure you want to continue connecting (yes/no)? yes
...
admin@ip-172-20-42-98:~$ 

Update

Cluster 의 구성을 변경할 수 있는데 아래 명령으로 수정할 수 있다.

kops edit cluster

vi 에디터로 구성 내용이 yaml 파일 형태로 열리는데 이는 s3 bucket 에 저장된 정보들을 이용해서 관리되고 있는 것이다. 변경이 필요한 항목을 수정하고 저장한다. 저장된 내용대로 실제 cluster 에 적용하기 위해서는 아래 명령으로 처리된다.

kops update cluster --yes

만일 kubernetes 에 마이크로 서비스들이 많이 작성되어 master 1대, node 2대로는 부족하다고 생각되어 node 를 하나 더 늘려야 한다면 아래 명령으로 수정할 수 있다. 여기서 ig 는 instance group 을 의미한다.

kops edit ig nodes

아래와 같이 클러스터 내의 서버들의 구성이 나타나는데 node 서버의 크기를 늘리거나 개수를 수정할 수 있다.

  machineType: t2.small
  maxSize: 3
  minSize: 3

각 node 서버들의 설정이 바꾸어 재시작 하려면 아래 명령을 사용한다. 서비스가 중단 되지 않도록 1대씩 돌아가면서 적용이 된다.

kops rolling-update cluster --yes

Default cluster

여러 클러스터를 사용하고 있다면 아래 명령으로 기본적으로 작업할 클러스터를 지정해 놓을 수 있다.

kubectl config set current-context k8s.test4kube.com

이 내용은 .kube/config 파일 안에 기록이 된다.

Reference

Install kubernetes on aws using kops

Getting started

Why and how do we run Kubernetes on the Spot instances

HA Masters, Private Networking and Bastion Support, Manage Multiple Instance groups and Labels