Skip to main content

2 posts tagged with "AWS"

View All Tags

· 12 min read

이번에는 Knative를 EKS에 구성해보려고 한다. 4월은 발표 및 여러가지 업무로 인해서 포스팅을 할 시간이 부족했지만 5월부터 조금씩 여유가 생겨서 더 바빠지기전에 좀 써보려고 한다. 사실 Facebook @최용호님께서 한번 해보는것도 좋겠다고 하셔서 테스트를 진행하였다.

Knative on EKS

제목만 보면 Lambda나 ECS, Batch 서비스가 있는데 왜 이걸 써야하지? 라는 생각부터 하는 사람도 있을것 같다. 하지만 이전 포스팅들과 발표에서도 여러번 이야기 한것처럼 Knative는 간단하게 서버리스 워크로드를 빌드, 배포, 관리하기 위한 Kubernetes기반 FaaS플랫폼이고 현재 CNCF Landscape에서 가장 빠른 속도로 개발되고 있는 오픈소스 프로젝트 중 하나이다.

EKS 배포

앞선 eksworkshop 포스팅에서처럼 간단한 배포를 위해 eksctl로 2-node 클러스터를 배포한다.
사전 준비사항은 이전 포스팅이나 https://eksctl.io/을 참고하자.

$ eksctl create cluster --name=eksworkshop-eksctl --nodes=2 --node-ami=auto

생성된 클러스터 상태를 확인한다.

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-24-168.ap-northeast-2.compute.internal Ready <none> 2m v1.11.9
ip-192-168-78-204.ap-northeast-2.compute.internal Ready <none> 2m v1.11.9

istio 설치

Knative는 istio 의존성을 가지고 있기 때문에 Istio를 먼저 배포한다. 물론 이전 포스팅에서 설명한것 처럼 Gloo를 사용해도 되지만 이번에는 Istio를 설치하였다.

$ kubectl apply -f https://github.com/knative/serving/releases/download/v0.5.0/istio-crds.yaml 
$ kubectl apply -f https://github.com/knative/serving/releases/download/v0.5.0/istio.yaml

배포된 Pods, Services, Replicasets 을 확인한다.

$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
cluster-local-gateway-65c8b667c8-269cf 1/1 Running 0 17m
istio-citadel-76bd44d8f7-5cltj 1/1 Running 0 17m
istio-cleanup-secrets-7jpth 0/1 Completed 0 17m
istio-egressgateway-b9d56b4f8-pdjhs 1/1 Running 0 17m
istio-galley-7db7db89db-5stkp 1/1 Running 0 17m
istio-ingressgateway-f77fbc787-npw9d 1/1 Running 0 17m
istio-pilot-69f975bf4f-4dq4d 2/2 Running 0 17m
istio-pilot-69f975bf4f-q9g8g 2/2 Running 0 16m
istio-pilot-69f975bf4f-tnm92 2/2 Running 0 16m
istio-policy-8db48cbcd-dl2th 2/2 Running 0 17m
istio-security-post-install-xv8z6 0/1 Completed 0 17m
istio-sidecar-injector-cd54ffccd-kj2n6 1/1 Running 0 17m
istio-telemetry-d78cd45db-8x2cw 2/2 Running 0 17m

$ kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-local-gateway ClusterIP 10.100.97.146 <none> 80/TCP,443/TCP,31400/TCP,15011/TCP,8060/TCP,15030/TCP,15031/TCP 17m
istio-citadel ClusterIP 10.100.147.235 <none> 8060/TCP,9093/TCP 17m
istio-egressgateway ClusterIP 10.100.25.44 <none> 80/TCP,443/TCP 17m
istio-galley ClusterIP 10.100.158.45 <none> 443/TCP,9093/TCP 17m
istio-ingressgateway LoadBalancer 10.100.62.157 a4e1d5201758f11e9b7f402c4d4b0376-510368564.ap-northeast-2.elb.amazonaws.com 80:31000/TCP,443:30753/TCP,31400:31922/TCP,15011:31331/TCP,8060:30389/TCP,853:30257/TCP,15030:30827/TCP,15031:30153/TCP 17m
istio-pilot ClusterIP 10.100.25.194 <none> 15010/TCP,15011/TCP,8080/TCP,9093/TCP 17m
istio-policy ClusterIP 10.100.73.149 <none> 9091/TCP,15004/TCP,9093/TCP 17m
istio-sidecar-injector ClusterIP 10.100.117.18 <none> 443/TCP 17m
istio-telemetry ClusterIP 10.100.87.12 <none> 9091/TCP,15004/TCP,9093/TCP,42422/TCP 17m

$ kubectl get rs -n istio-system
NAME DESIRED CURRENT READY AGE
cluster-local-gateway-65c8b667c8 1 1 1 17m
istio-citadel-76bd44d8f7 1 1 1 17m
istio-egressgateway-b9d56b4f8 1 1 1 17m
istio-galley-7db7db89db 1 1 1 17m
istio-ingressgateway-f77fbc787 1 1 1 17m
istio-pilot-69f975bf4f 3 3 3 17m
istio-policy-8db48cbcd 1 1 1 17m
istio-sidecar-injector-cd54ffccd 1 1 1 17m
istio-telemetry-d78cd45db 1 1 1 17m

Istio injection을 하기 위해 배포할 defaults namespace 전체에 Labeling을 한다.

$ kubectl label namespace default istio-injection=enabled
namespace/default labeled

$ kubectl get namespaces --show-labels
NAME STATUS AGE LABELS
default Active 43m istio-injection=enabled
istio-system Active 27m istio-injection=disabled
kube-public Active 43m <none>
kube-system Active 43m <none>

Knative 설치

build, evening, serving 및 모니터링 리소스를 배포한다.

kubectl apply -f https://github.com/knative/serving/releases/download/v0.5.0/serving.yaml \
-f https://github.com/knative/build/releases/download/v0.5.0/build.yaml \
-f https://github.com/knative/eventing/releases/download/v0.5.0/release.yaml \
-f https://github.com/knative/eventing-sources/releases/download/v0.5.0/eventing-sources.yaml \
-f https://github.com/knative/serving/releases/download/v0.5.0/monitoring.yaml \
-f https://raw.githubusercontent.com/knative/serving/v0.5.0/third_party/config/build/clusterrole.yaml

모든 Knative namespaces 및 resources를 확인한다.

$ kubectl get namespaces | grep knative
knative-build Active 8m
knative-eventing Active 8m
knative-monitoring Active 8m
knative-serving Active 8m
knative-sources Active 8m

$ kubectl get pods -n knative-serving
NAME READY STATUS RESTARTS AGE
activator-664b5b9598-dsjvq 2/2 Running 0 10m
autoscaler-64d5bd84b8-bqghq 2/2 Running 0 10m
controller-658b9d5c6c-tnwvz 1/1 Running 0 10m
webhook-5dffbfbb8b-525vt 1/1 Running 0 10m

$ kubectl get pods -n knative-build
NAME READY STATUS RESTARTS AGE
build-controller-86f5b5b96d-zg8j2 1/1 Running 0 11m
build-webhook-6fddd7c6df-68fkw 1/1 Running 0 11m

$ kubectl get pods -n knative-eventing
NAME READY STATUS RESTARTS AGE
eventing-controller-6fdccd8c95-bckws 1/1 Running 0 11m
in-memory-channel-controller-6fddb6655f-vbc64 1/1 Running 0 11m
in-memory-channel-dispatcher-7684cd7c7d-ftqhc 2/2 Running 2 11m
webhook-d496c66bd-688xz 1/1 Running 0 11m
$ kubectl get pods -n knative-monitoring 
NAME READY STATUS RESTARTS AGE
elasticsearch-logging-0 1/1 Running 0 14m
elasticsearch-logging-1 1/1 Running 0 12m
grafana-754bc795bb-wxwml 1/1 Running 0 14m
kibana-logging-7f7b9698bc-rrnw6 1/1 Running 0 14m
kube-state-metrics-5bccdf746f-fhv7t 4/4 Running 0 12m
node-exporter-w9jlq 2/2 Running 0 14m
node-exporter-wgv2j 2/2 Running 0 14m
prometheus-system-0 1/1 Running 0 14m
prometheus-system-1 1/1 Running 0 14m

모니터링 리소스도 확인한다. 위의 리소스를 보면 Fluentd가 배포되지 않은 상태이므로 DaemonSet으로 동작할수 있도록 아래와 같이 설정하면 DaemonSet을 확인할 수 있다.

$ kubectl label nodes --all beta.kubernetes.io/fluentd-ds-ready="true"

Build에서 사용할 Docker Credential 설정

일단 Knative Build를 수행할때 일반적으로 Container Registry를 많이 사용하기 때문에 Registry Credential 설정을 해야한다.

ECR의 경우 https://github.com/knative/build-templates의 ecr_helper를 사용하면 쉽게 ECR account를 설정할 수 있지만 Serving단계에서 401에러가 나는 이유를 잡지 못해서 일단 Dockerhub를 가지고 진행하였다.

간단한 데모코드는 아래 repository에 미리 작성해놨다.

https://github.com/ddiiwoong/hello-python.git

docker-secret.yaml 을 보면 dockerhub push를 위해 basic-auth를 수행하게 되는데 dockerhub id/password 를 base64로 encoding해서 Secret으로 저장한다.

apiVersion: v1
kind: Secret
metadata:
name: basic-user-pass
annotations:
build.knative.dev/docker-0: https://index.docker.io/v1/
type: kubernetes.io/basic-auth
data:
# Use 'echo -n "username" | base64' to generate this string
username: BASE64_ENCODED_USERNAME
# Use 'echo -n "password" | base64' to generate this string
password: BASE64_ENCODED_PASSWORD

그리고 ServiceAccount build-bot을 생성하기 위한 yaml (sa.yaml)를 작성한다.

apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
secrets:
- name: basic-user-pass

위에서 작성한 Secret(basic-user-pass)과 ServiceAccount(build-bot)를 배포한다.

$ kubectl apply -f docker-secret.yaml
secret "basic-user-pass" created
$ kubectl apply -f sa.yaml
serviceaccount "build-bot" created

저장된 Secret(basic-user-pass)과 ServiceAccount(build-bot)를 확인한다.

$ kubectl get secret
NAME TYPE DATA AGE
basic-user-pass kubernetes.io/basic-auth 2 2h
build-bot-token-gfkg9 kubernetes.io/service-account-token 3 2h
builder-token-kp7ww kubernetes.io/service-account-token 3 10h
default-token-9cpp5 kubernetes.io/service-account-token 3 10h
ecr-creds kubernetes.io/basic-auth 2 10h
istio.build-bot istio.io/key-and-cert 3 2h
istio.builder istio.io/key-and-cert 3 10h
istio.default istio.io/key-and-cert 3 10h
istio.knative-serve istio.io/key-and-cert 3 2h
knative-serve-token-9j82l kubernetes.io/service-account-token 3 2h

$ kubectl get sa
NAME SECRETS AGE
build-bot 2 2h
builder 2 10h
default 1 10h
knative-serve 2 2h

Python 코드 및 Dockerfile 작성

TARGET 환경변수를 받아서 Hello World와 같이 출력하는 간단한 Flask기반 앱을 작성한다.

간단한 데모코드는 아래 repository에 미리 작성해놨다.

https://github.com/ddiiwoong/hello-python.git

import os

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
target = os.environ.get('TARGET', 'NOT SPECIFIED')
return 'Hello World: {}!\n'.format(target)

if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

위 앱(app.py)을 배포하는 Dockerfile을 작성한다.

FROM python:alpine

ENV APP_HOME /app
COPY . $APP_HOME
WORKDIR $APP_HOME

RUN pip install Flask

ENTRYPOINT ["python"]
CMD ["app.py"]

Knative Build

미리 Dockerhub에서 hello-python repository(docker.io/ddiiwoong/hello-python)를 생성한다.
그리고 위에서 생성한 build-bot 계정과 image tag hello-python정보를 Build template에 작성하여 배포한다.
아래 Knative Build 과정은 kaniko executor를 사용하여 다음과 같은 과정을 수행한다.

  1. spec.source 에서 Source Clone (git)를 수행하고 이후
  2. spec.steps 에서 Docker Build, Tag, Registry Login, Push를 수행한다.
apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
name: python-build
spec:
serviceAccountName: build-bot
source:
git:
url: https://github.com/ddiiwoong/hello-python.git
revision: master
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:v0.1.0
args:
- --dockerfile=/workspace/Dockerfile
- --destination=docker.io/ddiiwoong/hello-python:latest

build를 수행한다.

$ kubectl apply -f build.yaml
build.build.knative.dev/python-build created

$ kubectl get build
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
python-build True 18m

정상적으로 Build가 완료되면 Dockerhub에 정의한 TAG(ddiiwoong/hello-python)로 이미지가 등록된걸 확인할 수 있다.

$ docker pull ddiiwoong/hello-python
Using default tag: latest
latest: Pulling from ddiiwoong/hello-python
e7c96db7181b: Pull complete
799a5534f213: Pull complete
913b50bbe755: Pull complete
11154abc6081: Pull complete
c805e63f69fe: Pull complete
6eabcf0f7a50: Pull complete
74101057f4ec: Pull complete
Digest: sha256:51dc4a7ce38a5e7894adcfc00eaee6c5ea6aca1ef6c7521f9b7ea6382c013b9b
Status: Downloaded newer image for ddiiwoong/hello-python:latest

Knative Serving 으로 배포

service.yaml

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: helloworld-python
namespace: default
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: ddiiwoong/hello-python:latest
env:
- name: TARGET
value: "Python Sample v1 with Knative on EKS"

빌드된 image (ddiiwoong/hello-python:latest)로 Knative Service를 생성한다.

$ kubectl apply -f service.yaml
service.serving.knative.dev/helloworld-python created

istio-system Namespace에 istio-ingressgateway Service를 확인한다.

kubectl get svc istio-ingressgateway --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.100.208.80 a220723d475df11e980220a02e220b34-2021915778.ap-northeast-2.elb.amazonaws.com 80:31581/TCP,443:31490/TCP,31400:30367/TCP,15011:32495/TCP,8060:31418/TCP,853:30310/TCP,15030:32405/TCP,15031:31410/TCP 13h

ALB: a220723d475df11e980220a02e220b34-2021915778.ap-northeast-2.elb.amazonaws.com

위와 같이 AWS LoadBalancer로 배포면 ALB가 자동으로 생성되므로 추후 eksctl로 클러스터를 삭제하기 전에 반드시 LoadBalancer 형태로 배포된 서비스를 삭제하고 진행해야 한다.

Knative Service를 확인한다.

$ kubectl get ksvc
NAME DOMAIN LATESTCREATED LATESTREADY READY REASON
helloworld-python helloworld-python.default.example.com helloworld-python-4rw95 helloworld-python-4rw95 True

위에서 얻은 두가지 정보(LoadBalancer, Domain)로 생성된 app을 테스트한다.
Knative는 내부적으로 example.com이라고 하는 기본 domain을 사용하므로 내부적으로는 helloworld-python.default.example.com으로 curl을 실행하게 된다.

$ curl -H "Host:helloworld-python.default.example.com" http://a220723d475df11e980220a02e220b34-2021915778.ap-northeast-2.elb.amazonaws.com
Hello World: Python Sample v1 with Knative on EKS!

Cold Start(default timeout 5분) 때문에 잠시 응답이 늦어질 수도 있지만(2-5초) 잠시 기다리면 위처럼 결과를 확인할 수 있다.

정리

위에서도 잠깐 언급했지만 Lambda나 ECS, Batch 서비스가 있는데 Knative on EKS 를 구지 왜 하느냐라고 궁금해하는 분들이 계실지도 모른다. 하지만 다들 아래와 같은 고민을 해봤을거라 생각한다.

컨테이너와 Kubernetes가 DevOps도구로서의 표준이 되어가는 시대에 Lambda를 쓸지 오픈소스를 쓸지에 대한 고민은 결국 이식성과 벤더 종속성을 제거하고 운영효율화 측면에서 그 답을 찾을수 있을것 같다.

현재 몸담고 있는 최근 프로젝트에서 Lambda, ECS, Batch 등을 사용하는 경우가 많아졌는데 실제 엔터프라이즈에서 정해진 자원내에서 정해진 일을 할때는 매니지드 서비스가 적합하다고 생각한다. 하지만 On-Premise 또는 그에 준하는 Kubernetes 클러스터를 운영하는 조직에서는 Knative를 사용하여 컨테이너 기반 서비리스 워크로드를 구현하는 것이 향후 Hybrid 관점에서 확장성과 벤더 종속성을 제거하는데 큰 도움이 될것이라 생각한다.

조금씩 Kubernetes 및 생태계 Learning에 대한 피로도가 증가하고 있고 Hype Driven Development(설레발 주도개발)가 되는것 같아서 아쉬운 부분은 있지만 현재 가장 핫한 기술이고 관심도가 높기 때문에 배워두면 언젠가는 써먹게 될거라 확신한다.

다시한번 Conference driven development(architecture)가 되지 않도록 자중하고 Loudest Guy가 되지 않도록 조심해야할 것 같다.

· 15 min read

Amazon EKS (Elastic Container Service for Kubernetes)

Kubernetes Managed Service인 Amazon EKS가 2018년 7월 출시되고 2019년 1월 정식으로 서울리전에 출시되었다. 개인적으로 완전관리형 Kubernetes 출시가 늦어져서 AWS 행보가 다소 늦다고 생각은 했으나 ALB와 VPC연동, 여러가지 기존 OpenSource와의 연결고리를 배제하고 자체 Managed서비스와 연동할것들이 많기 때문에 당연히 타사에 비해 늦어진걸로 보인다. 언제나 그랬지만 오픈소스를 받아들이는 느낌이 아니라 뭔가 완성된 제품을 쓰는 느낌(?)이다. 물론 불편한 부분과 감수해야할 내용들은 조금 있지만 기존 AWS 충성 User에게 호응을 얻을수 있기 때문이 아닐까라는 생각을 해보면서 포스팅을 시작하려고 한다.

오픈소스가 아닌 Managed서비스에 대한 리뷰는 처음이지만 4월 10일 AWS판교소모임 발표도 있고, 실제 고려중인 아키텍처에 포함이 되어야 하는 EKS에 대해서 살펴보고 eskworkshop 튜토리얼을 실행해보면서 다른 관리형 Kubernetes 서비스들에 비해 어떤 사항을 좀더 고민해야 하는지 정리해보고 넘어가면 좋을듯 하다.

eksworkshop.com

https://eksworkshop.com/
Kubernete를 처음접하는 유저를 위한 기본 개념과 아키텍처, 그리고 VPC, ALB를 활용하여 EKS에 대한 설치, 구성, 데모앱 배포 등을 해볼수 있는 튜토리얼 사이트이다.

AWSKRUG에서 한글화 작업도 진행중이다. 한글화 링크

eksworkshop 따라하기전 사전 준비사항

eksworkshop에서는 기본적으로 workshop이라는 신규 IAM 계정을 생성하고 Cloud9 Workspace 와 몇가지 설정들을 진행하지만 AWS판교소모임을 위해 최대한 비용이 드는 구성요소를 배제하고 작성하고자 한다.

AWS account

Free Tier는 EKS를 자유롭게 활용할수 없다.
관련 issue - https://github.com/aws/containers-roadmap/issues/78

실제 사용중인 계정이나 Credit이 확보된 계정이 필요하다.

IAM 설정 (JSON template)

EKSworkshop에서는 Full administrator 계정을 필요로 하지만 eksctl로 배포를 진행하므로 그 기준으로 IAM설정을 진행한다.

terraform eks iam 설정을 참고하려고 했지만 eksctl과 terraform과의 약간 다른 방식의 배포로 인해 어쩔수없이 EKS Full Access권한을 할당하였다.
(다른 유경험자의 도움이 필요한 상황 ㅠㅠ)

자세한 JSON 내용은 링크를 참고한다.

kubectl, aws-iam-authenticator

  • kubectl : kubernetes CLI
  • aws-iam-authenticator : AWS IAM Authenticator CLI

kubectl config를 저장하기 위해 .kube directory를 생성

$ mkdir -p ~/.kube

kubectl 설치 (linux)

$ sudo curl --silent --location -o /usr/local/bin/kubectl "https://amazon-eks.s3-us-west-2.amazonaws.com/1.11.5/2018-12-06/bin/linux/amd64/kubectl"
$ sudo chmod +x /usr/local/bin/kubectl

kubectl 설치 (MacOS Homebrew)

MacOS는 brew로 설치하였다.
https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-with-homebrew-on-macos

$ brew install kubernetes-cli

kubectl 설치 (windows PowerShell)

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/install-kubectl.html

curl -o kubectl.exe https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/windows/amd64/kubectl.exe

kubectl 설치 확인

현재 MacOS에서는 1.11.7 버전이 설치되어 있다. (다른경로로 설치됨)

$ kubectl version --short --client
Client Version: v1.11.7-dispatcher

aws-iam-authenticator 설치

Amazon EKS는 IAM을 사용하여 Kubernetes용 AWS IAM Authenticator를 통해 Kubernetes 클러스터에 인증을 제공한다. Go(버전 1.7이상)가 설치되어 있으면 아래와 같이 진행하면 된다.

$ go get -u -v github.com/kubernetes-sigs/aws-iam-authenticator/cmd/aws-iam-authenticator
$ sudo mv ~/go/bin/aws-iam-authenticator /usr/local/bin/aws-iam-authenticator

만약 Go설치가 안되어 있다면 다음 링크를 통해 설치 진행할수 있다.
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/install-aws-iam-authenticator.html

aws-iam-authenticator binary 다운로드

Linux: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/linux/amd64/aws-iam-authenticator
MacOS: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/darwin/amd64/aws-iam-authenticator
Windows: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/windows/amd64/aws-iam-authenticator.exe

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
MacOS bash 환경변수 추가
$ echo 'export PATH=$HOME/bin:$PATH' >> ~/.bash_profile
MacOS zsh 환경변수 추가
$ echo 'export PATH=$HOME/bin:$PATH' >> ~/.zshrc

aws-iam-authenticator binary 확인

$ aws-iam-authenticator help

eksctl

mascot

eksctl은 weaveworks에서 contribute하고 있는 오픈소스로 EKS 클러스터를 생성하는 간단한 CLI 도구이다. Go로 작성되어 있고 CloudFormation을 기본으로 동작한다.

https://eksctl.io/
https://github.com/weaveworks/eksctl

eksctl binary 다운로드

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

MacOS Homebrew 설치

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

Windows 설치 (PowerShell, chocolatey)

chocolatey install eksctl

eksctl 동작확인

$ eksctl version

CLI API 자격증명 구성

사전설정한 aws configure가 있는지 확인. 기존 Terraform이나 kops 사용한적이 있으면 건너뛰어도 된다.

$ ls  ~/.aws

없을경우 aws 자격증명을 생성한다.

~/.aws/credentials

[default]
aws_access_key_id={EXAMPLE}
aws_secret_access_key={EXAMPLEKEY}

~/.aws/config

[default]
region=ap-northeast-2
output=json

EKS 배포

kubectl, aws-iam-authenticator, eksctl, AWS 자격증명 환경까지 구성되어 있으면 바로 배포가 가능하다.

$ eksctl create cluster --name=eksworkshop-eksctl --nodes=3 --node-ami=auto
[] using region ap-northeast-2
[] setting availability zones to [ap-northeast-2a ap-northeast-2c ap-northeast-2a]
[] subnets for ap-northeast-2a - public:192.168.0.0/19 private:192.168.96.0/19
[] subnets for ap-northeast-2c - public:192.168.32.0/19 private:192.168.128.0/19
[] subnets for ap-northeast-2a - public:192.168.64.0/19 private:192.168.160.0/19
[] nodegroup "ng-cfb3cb01" will use "ami-0c7972077aa002104" [AmazonLinux2/1.11]
[] creating EKS cluster "eksworkshop-eksctl" in "ap-northeast-2" region
[] will create 2 separate CloudFormation stacks for cluster itself and the initial nodegroup
[] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-2 --name=eksworkshop-eksctl'
[] creating cluster stack "eksctl-eksworkshop-eksctl-cluster"
[] creating nodegroup stack "eksctl-eksworkshop-eksctl-nodegroup-ng-cfb3cb01"
[] --nodes-min=2 was set automatically
[] --nodes-max=2 was set automatically
[] all EKS cluster resource for "eksworkshop-eksctl" had been created
[] saved kubeconfig as "/Users/ddii/.kube/config"
[] nodegroup "ng-cfb3cb01" has 0 node(s)
[] waiting for at least 2 node(s) to become ready in "ng-cfb3cb01"
[] nodegroup "ng-cfb3cb01" has 2 node(s)
[] node "ip-192-168-42-42.ap-northeast-2.compute.internal" is ready
[] node "ip-192-168-66-165.ap-northeast-2.compute.internal" is ready
[] kubectl command should work with "/Users/ddii/.kube/config", try 'kubectl get nodes'
[] EKS cluster "eksworkshop-eksctl" in "ap-northeast-2" region is ready

서울리전(ap-northeast-2)기준 약 15-20분이 소요되며 eksctl 기본 설정값은 다음과 같다.

  • 클러스터명은 자동생성, --name 옵션으로 지정가능 (eksworkshop-eksctl)
  • CloudFormation : eksctl-{$Cluster_Name}-cluster
  • m5.large * 2 instances (EKS Instance Type NodeInstanceType.AllowedValues 참고)
  • Default AMI : AWS EKS AMI (custom EKS AMI 가능 - Packer활용)
  • Default Region : us-west-2
  • dedicated VPC : 192.168.0.0/16
  • kubernetes version : 1.11.x (EKS Version 참고)
  • StorageClass : gp2 (AWS EBS 참고)
  • CNI : Amazon VPC
  • Node Autoscaler : --node-min, --node-max Auto Scaling 설정
  • 기본 Pod 개수 : 참고
  • nodegroup : worker가 포함되는 group
  • kubeconfig : ~/.kube/config 로 통합됨

Config File 사용

https://github.com/weaveworks/eksctl/tree/master/examples를 참고하여 YAML형태로 작성하여 배포가능하다.

$ eksctl create cluster -f example.yaml

기존에 관리하는 VPC subnet정보 및 AutoScaling, AZ(availabilityZones)설정, nodegroup 관리, node Instance에 preBootstrapCommand등을 아래 예시와 같이 미리 작성하면 GitOps측면에서 활용도가 더욱 높아질수 있다.

05-advanced-nodegroups.yaml

# An advanced example of ClusterConfig object with customised nodegroups:
---
apiVersion: eksctl.io/v1alpha4
kind: ClusterConfig

metadata:
name: cluster-5
region: eu-west-2

nodeGroups:
- name: ng1-public
instanceType: m5.xlarge
minSize: 2
maxSize: 8
labels:
nodegroup-type: frontend-workloads
iam:
withAddonPolicies:
autoScaler: true

- name: ng2-private-a
instanceType: m5.large
desiredCapacity: 2
labels:
nodegroup-type: backend-cluster-addons
privateNetworking: true
preBootsrapCommand:
# allow docker registries to be deployed as cluster service
- 'echo {\"insecure-registries\": [\"172.20.0.0/16\",\"10.100.0.0/16\"]} > /etc/docker/daemon.json'
- "systemctl restart docker"

- name: ng3-private-b
instanceType: c3.8xlarge
desiredCapacity: 4
labels:
nodegroup-type: very-special-science-workloads
privateNetworking: true
availabilityZones: ["eu-west-2a"] # use single AZ to optimise data transfer between isntances
preBootstrapCommand:
# disable hyperthreading
- "for n in $(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | cut -s -d, -f2- | tr ',' '\n' | sort -un); do echo 0 > /sys/devices/system/cpu/cpu${n}/online; done"

# cluster AZs must be set explicitly for single AZ nodegroup example to work
availabilityZones: ["eu-west-2a", "eu-west-2b", "eu-west-2c"]

Kubernetes 대시보드 배포

Kubernetes 공식 대시보드는 기본으로 배포되지 않기 때문에 수동으로 배포해야한다. 설치 방법은 공식 문서에서 확인가능하다.

위에서 구성된 클러스터에서 Kubernetes 대시보드를 배포한다.

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

접속을 위해 kube-proxy 기능을 활용하여 8080포트로 expose를 진행한다. 모든 인터페이스에서 필터링없이 접속이 가능하도록 옵션을 지정한다. 아래 명령은 터미널에서 백그라운드로 계속 동작한다.

$ kubectl proxy --port=8080 --address='0.0.0.0' --disable-filter=true &
W0328 16:39:09.061754 9100 proxy.go:139] Request filter disabled, your proxy is vulnerable to XSRF attacks, please be cautious

TOKEN으로 접속하기 위해 aws-iam-authenticator를 통해 해당 클러스터 token을 확인한다.

$ aws-iam-authenticator token -i eksworkshop-eksctl --token-only
k8s-aws-v1.aHR0cHM6Ly9zdHMuYXAtbm9ydGhlYXN0LTIuYW1hem9uYXdzLmNvbS8_QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNSZYLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFKMjVNVjJSVVZQNlRWTURBJTJGMjAxOTAzMjglMkZhcC1ub3J0aGVhc3QtMiUyRnN0cyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMTkwMzI4VDA3NDEwNVomWC1BbXotRXhwaXJlcz0wJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TaWduYXR1cmU9Yjc0NzkzYzUwOTU5NDYwMzMxMjY2YjExYWY4ODBkM2Q2OWQ5MWRhYzFhZWY1NjZmZTAwNTNlNWY2MTM0NGFlZQ

그냥 localhost:8080 으로만 접속하면 구성된 클러스터 kube API list를 확인되므로 아래 경로로 접속한다.
위에서 출력된 TOKEN값으로 로그인한다. Token 세션 Timeout이 있으니 세션만료시 aws-iam-authenticator 명령을 통해 갱신값을 입력하면 된다.

http://localhost:8080/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login

dashboard

Microservice app 배포

가장 기본적인 Sock Shop을 배포하기 위해 Git Clone 수행

$ git clone https://github.com/microservices-demo/microservices-demo.git sockshop
$ cd sockshop/deploy/kubernetes

NodePort로 되어있는 Front-End Service를 LoadBalancer로 수정한다.

$ sed -i 's/NodePort/LoadBalancer/g' complete-demo.yaml
$ cat complete-demo.yaml | grep LoadBalancer
type: LoadBalancer

namespace 생성 및 sock-shop 배포

$ kubectl create namespace sock-shop
$ kubectl apply -f complete-demo.yaml
$ kubectl get all

서비스 접속확인을 위해서는 ALB배포시간(DNS전파)이 일정 소요되므로 잠시후 접속을 시도한다.

$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
carts ClusterIP 10.100.84.58 <none> 80/TCP 1h
carts-db ClusterIP 10.100.227.156 <none> 27017/TCP 1h
catalogue ClusterIP 10.100.206.52 <none> 80/TCP 1h
catalogue-db ClusterIP 10.100.119.66 <none> 3306/TCP 1h
front-end LoadBalancer 10.100.249.164 a4c42cfe951be11e9bb8c0a8cd8a2e5d-8156023.ap-northeast-2.elb.amazonaws.com 80:30001/TCP 1h
orders ClusterIP 10.100.160.17 <none> 80/TCP 1h
orders-db ClusterIP 10.100.70.203 <none> 27017/TCP 1h
payment ClusterIP 10.100.57.233 <none> 80/TCP 1h
queue-master ClusterIP 10.100.146.109 <none> 80/TCP 1h
rabbitmq ClusterIP 10.100.32.115 <none> 5672/TCP 1h
shipping ClusterIP 10.100.180.174 <none> 80/TCP 1h
user ClusterIP 10.100.211.41 <none> 80/TCP 1h
user-db ClusterIP 10.100.87.142 <none> 27017/TCP 1h

브라우저에서 ALB주소 a4c42cfe951be11e9bb8c0a8cd8a2e5d-8156023.ap-northeast-2.elb.amazonaws.com 로 접속하여 sock-shop Demo Web을 확인할수 있다.

sockshop

EKS 클러스터 및 삭제

위에서 외부접속을 위해 LoadBalancer를 수동으로 설정하였으므로 EC2 - Load Balancer서 프로비저닝된 ALB를 삭제하고 진행해야 한다.

클러스터에서 실행 중인 모든 서비스를 다시 확인하고 EXTERNAL-IP값과 연결된 모든 서비스를 삭제한다.

$ kubectl get svc --all-namespaces
$ kubectl delete svc front-end

ALB와 VPC 삭제가 완료된것을 확인하고 클러스터를 삭제하자.

$ eksctl delete cluster --name=eksworkshop-eksctl
[] deleting EKS cluster "eksworkshop-eksctl"
[] will delete stack "eksctl-eksworkshop-eksctl-nodegroup-ng-3af535b7"
[] waiting for stack "eksctl-eksworkshop-eksctl-nodegroup-ng-3af535b7" to get deleted
[] will delete stack "eksctl-eksworkshop-eksctl-cluster"
[] kubeconfig has been updated
[] the following EKS cluster resource(s) for "eksworkshop-eksctl" will be deleted: cluster. If in doubt, check CloudFormation console

정리

서울 리전(ap-northeast-2)에 EKS가 오픈되고 Production환경을 EKS로 넘어가는 기업들이 많아지고 있는건 아주 긍정적인 현상이다.
또한 엄청난 속도의 기술개발과 다양한 툴들로 Kubernetes Cluster를 구성하거나 Microservice형태의 App을 배포하는것은 점점 대중화 되어가고 있다.
실제 Production에서 구현을 하기 위해서는 보안 및 성능을 동시에 고려한 네트워크(CNI), Ingress 설정이나 전체 클러스터 퍼포먼스 측면에서의 파라미터 튜닝이 더욱 더 중요해지고 관련된 DevOps(SRE) 인력들의 중요도가 높아질것은 분명해 보인다.

EKS를 오픈소스 측면에서 고려했을때에는 예전에 페이스북이나 다른곳에서 종종 이야기 했던것처럼 AWS 고유의 Lock-in 전략을 엄청나게 고민하고 발표한듯한 생각이 한 느낌을 지울수는 없는건 사실이지만 훌륭한 제품인건 확실하고 단기간에 서비스 성장속도를 낼 수 있는 서비스라 생각한다.

마지막으로 Managed Kubernetes의 선택은 엔지니어의 몫으로 보고 각 벤더별 비교한 아래 링크를 참조해서 선정 기준을 잡으면 더욱 좋을것 같다.
https://docs.google.com/spreadsheets/d/1U0x4-NQegEPGM7eVTKJemhkPy18LWuHW5vX8uZzqzYo/edit#gid=0