Minikube에 Knative 설치해보고 처음으로 앱 배포해보기

knative 0.6., docker engine 18.06.2-ce, kubernetes 1.12.0, Istio 1.0.7, minikube v1.0.0 , macOS Mojave 10.14.4(18E226)

Knativ는 AWS의 람다(Lambda)나, Google의 펑션(Function) 같은 Serverless 서비스를 할 수 있도록 워크로드를 구축 및 관리하는 Kubernetes 기반 오픈소스 플랫폼입니다. 이에 minikuke를 활용해 로컬에 설치해보고 샘플 앱을 배포 및 실행을 통해 Knative 의 개념 및 동작원리를 이해하고 Knative 하에서 Blue/Green Deployment 가 어떤 방식으로 정의되고 동작되는지 확인해 보고자 합니다.

Install


개요

  • with Istio, with Gloo 두가지 인스톨 방법이 있음

  • Gloo 는 envoy-based api gateway 로 Knative “Eventing” 컴포넌트를 지원하지 않으며 서비스메시를 필요로하지 않거나 lightweight 한 기능만 필요할 경우 사용

  • Installing Knative with Istio

    • Comprehensive Install - 포괄적 설치
    • Limited Install - observability plugin 제외, disk space 최소화 설치
    • Custom Install - 컴포넌트와 and observability plugin 선택 설치
  • v0.6 공식 문서 Install 가이드에 따라 MacOS에서 아래와 같이 VirtualBox 및 K8s v1.14.0 환경으로 클러스터를 생성하고 설치를 진행했지만 성공하지 못했습니다.

$ minikube start --memory=8192 --cpus=6 --disk-size=30g  -p knative
  • “Comprehensive Install”은 Request 가 크기 때문에 minikube 에서 설치는 불가능했을 뿐만 아니라 VirtualBox, K8s 버전에 따라 설치가 진행되지 않아서 아래와 같이 몇가지 조정해 주었습니다.

    • memory를 8g 에서 10g로 cpu 6에서 8로 업그레이드
    • Event, Monitoring 컴포넌트 제외
    • apiserver.enable-admission-plugins 모두 제외
    • VirtualBox 대신 hyperkit 드라이버 사용 (공식문서)
    • K8s v1.12.0 로 다운그레이드 (공식문서)

클러스터 생성

  • hyperkit 드라이버 설치
$ brew install hyperkit

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \
&& sudo install -o root -g wheel -m 4755 docker-machine-driver-hyperkit /usr/local/bin/
  • minikube 클러스터 생성
$ minikube start --memory=10240 --cpus=8 --disk-size=30g -p knative \
  --kubernetes-version=v1.12.0 \
  --vm-driver=hyperkit

Istio 설치

  • Istio LoadBalancer 를 NodePort로 변경
$ kubectl apply -f https://raw.githubusercontent.com/knative/serving/v0.5.2/third_party/istio-1.0.7/istio-crds.yaml

$ curl -L https://raw.githubusercontent.com/knative/serving/v0.5.2/third_party/istio-1.0.7/istio.yaml \
  | sed 's/LoadBalancer/NodePort/' \
  | kubectl apply -f -
  • 파드 Running/Complete 상태 확인
$ kubectl get pods -n istio-system --watch
  • sidecar injection
$ kubectl label namespace default istio-injection=enabled

Install Knative

  • Knative CRDs 등록
$ kubectl apply --selector knative.dev/crd-install=true \
-f https://github.com/knative/serving/releases/download/v0.6.0/serving.yaml \
-f https://github.com/knative/build/releases/download/v0.5.0/build.yaml \
-f https://raw.githubusercontent.com/knative/serving/v0.6.0/third_party/config/build/clusterrole.yaml
  • Knative 설치 (Event, Monitoring 컴포넌트 제외)
$ kubectl apply --selector networking.knative.dev/certificate-provider!=cert-manager \
-f https://github.com/knative/serving/releases/download/v0.6.0/serving.yaml \
-f https://github.com/knative/build/releases/download/v0.5.0/build.yaml \
-f https://raw.githubusercontent.com/knative/serving/v0.6.0/third_party/config/build/clusterrole.yaml
  • 파드 Running/Complete 상태 확인
$ kubectl get pod --all-namespaces --watch

샘플 앱 (helloworld-go) 배포 및 실행 해보기


배포

  • 샘플 앱을 deploy 하기 위해서 “Service”가 정의된 yaml file 을 생성합니다.
$ vi service.yaml
apiVersion: serving.knative.dev/v1alpha1 # Current version of Knative
kind: Service
metadata:
  name: helloworld-go # The name of the app
  namespace: default # The namespace the app will use
spec:
  template:
    spec:
      containers:
        - image: gcr.io/knative-samples/helloworld-go # The URL to the image of the app
          env:
            - name: TARGET # The environment variable printed out by the sample app
              value: "Go Sample v1"
$ kubectl apply -f service.yaml

실행 준비

  • default 네임스페이스에 파드가 없는 상태 확인
  • 배포 이후 파드가 조회 되지만 일정 시간 이후에는 파드가 자동으로 Terminating 됩니다.
$ kubectl get pod

No resources found.
  • Ingressgateway URL과 라우팅시 필요한 host URL을 정의합니다.
$ export HOST_URL=$(kubectl get route helloworld-go  -o jsonpath='{.status.domain}')
$ export IP_ADDRESS=$(kubectl get node -o 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc istio-ingressgateway -n istio-system -o 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')

실행 및 결과 확인

helloworld-go 앱은 사용자 요청에 따라 환경변수 “TARGET” 에 정의 된 “Hello World: Go Sample v1!”라는 문자열이 클라이언트로 리턴하는 로직을 가지고 있습니다.

아래와 같이 사용자가 URL 로 요청하면 Header의 Host 명에 정의된 도메인으로 (helloworld-go 서비스)로 요청을 라우팅하게 되고 Knative는 실행 될 파드 (“gcr.io/knative-samples/helloworld-go”)가 네임스페이스에 존재하지 않을 경우 실 시간으로 해당 파드를 먼저 설치하게 됩니다.

이후에 또 다른 실행 요청이 없을 경우 helloworld-go 파드는 삭제됩니다.

  • 사용자 요청 수행합니다.
$ curl -H "Host: ${HOST_URL}" http://${IP_ADDRESS}

Hello World: Go Sample v1!
  • default 네임스페이스에 helloworld-go 파드가 새로 생성되었음을 확인합니다.
$ kubectl get pod

NAME                                              READY   STATUS    RESTARTS   AGE
helloworld-go-v74pk-deployment-5bdd97f8b7-977b5   3/3     Running   0          23s
  • 동일한 요청을 했을 경우 설치 과정이 없으므로 이전에 비해서 빠른 응답시간을 보여준다.
$ curl -H "Host: ${HOST_URL}" http://${IP_ADDRESS}

Hello World: Go Sample v1!
  • 추가 요청이 없다면 잠시 후 default 네임스페이스에 helloworld-go 파드 삭제되었음을 알 수 있습니다.
$ kubectl get pod

No resources found.

Clean-up

$ kubectl delete -f service.yaml

Blue-Green Deployments 전략 맛보기

  • Blue-Green Deployments란 무중단 배포를 위한 방안
  • 현재버전을 Blue, 새버전을 Green으로 정하여 Green 으로 점점 더 많은 트래픽을 보내는 방법
  • 만일 문제가 생길경우 Green 버전을 철수하여 빠르게 복구
  • 응용 : Canary Releases, A/B Testing

시나리오

  1. Blue(v1) 앱을 배포해보고 URL 요청하여 class='blue' 코드를 포함하여 결과가 리턴 되는 지 확인합니다.
  2. Green(v2) 앱을 배포하고 라우팅 룰을 v1:v2 = 50:50 으로 배포하도록 정의합니다.
  3. URL 요청하여 class='blue', class='green' 코드가 50:50 으로 리턴되는지 확인합니다.

1단계 - v1 배포

  • Blue (v1, route-demo-config-v1) app을 배포
$ kubectl apply -f - <<EOF
apiVersion: serving.knative.dev/v1alpha1
kind: Configuration
metadata:
  name: route-demo-config-v1
  namespace: default
spec:
  revisionTemplate:
    metadata:
      labels:
        knative.dev/type: container
    spec:
      container:
        image: gcr.io/knative-samples/knative-route-demo:blue
        imagePullPolicy: Always
        env:
          - name: T_VERSION
            value: "blue"
EOF
  • Route 리소스 배포
$ kubectl apply -f - <<EOF
apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
  name: route-demo
  namespace: default
spec:
  traffic:
  - configurationName: route-demo-config-v1
    percent: 100
EOF
  • kubectl 로 default 네임스페이스에 deploy 상태 확인
$ kubectl get config

NAME                   LATESTCREATED                LATESTREADY                  READY   REASON
helloworld-go          helloworld-go-v74pk          helloworld-go-v74pk          True
route-demo-config-v1   route-demo-config-v1-nvfw4   route-demo-config-v1-nvfw4   True

$ kubectl get route

NAME            URL                                        READY   REASON
helloworld-go   http://helloworld-go.default.example.com   True
route-demo      http://route-demo.default.example.com      True

  • 라우팅을 위한 HOST_URL과 Ingressgateway 주소인 IP_ADDRESS 변수를 정의
$ export HOST_URL=$(kubectl get route route-demo  -o jsonpath='{.status.domain}')

$ export IP_ADDRESS=$(kubectl get node -o 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc istio-ingressgateway -n istio-system -o 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')

$ 2초마다 10번의 트래픽 생성하여 결과 HTML 에서 class='blue' 로 지정되는것을 확인합니다.

$ for i in {1..10}; do curl -i -H "Host: ${HOST_URL}" http://${IP_ADDRESS}; sleep 2; done

2단계 - v2 배포 하고 v1:v2=50:50 으로 라우팅 정의

  • Green (v2, route-demo-config-v2) app을 배포
$ kubectl apply -f - <<EOF
apiVersion: serving.knative.dev/v1alpha1
kind: Configuration
metadata:
  name: route-demo-config-v2
  namespace: default
spec:
  revisionTemplate:
    metadata:
      labels:
        knative.dev/type: container
    spec:
      container:
        image: gcr.io/knative-samples/knative-route-demo:green # URL to the new version of the sample app docker image
        imagePullPolicy: Always
        env:
          - name: T_VERSION
            value: "green" # Updated value for the T_VERSION environment variable
EOF
  • kubectl 로 default 네임스페이스에 deploy 상태 확인
$ kubectl get config

NAME                   LATESTCREATED                LATESTREADY                  READY   REASON
helloworld-go          helloworld-go-4nht8          helloworld-go-4nht8          True
route-demo-config-v1   route-demo-config-v1-ckb5s   route-demo-config-v1-ckb5s   True
route-demo-config-v2   route-demo-config-v2-98lln   route-demo-config-v2-98lln   True
  • route-demo Route를 v1, v2 를 50 : 50 으로 라우팅 하도록 수정합니다.
$ kubectl apply -f - <<EOF
apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
  name: route-demo
  namespace: default
spec:
  traffic:
  - configurationName: route-demo-config-v1
    percent: 50
  - configurationName: route-demo-config-v2
    percent: 50
    name: v2
EOF

$ 2초마다 10번의 트래픽 생성하여 결과 HTML 에서 class='blue', class='green' 로 50:50으로 보여지는 것을 확인

$ for i in {1..10}; do curl -i -H "Host: ${HOST_URL}" http://${IP_ADDRESS}; sleep 2; done

Clean-up

$ kubectl delete config route-demo-config-v1 route-demo-config-v2
$ kubectl delete route route-demo

마치면서


아래와 같은 사항을 확인하였다.

  • Knative는 Kubernetes, Istio 기반의 Serverless 오픈소스 플랫폼입니다. Istio 대신 Gloo를 활용할 경우 기능을 제한됩니다.
  • 사용자의 요청에 따라서 실시간으로 Running 되어야할 POD가 Create 되고 작업 완료 후 Terminating 됩니다.
  • Knative의 Serving 컴포넌트의 Configuration, Route CRDs 를 통해 Knative Blue/Green Deployment 전략을 손쉽게 실현할 수 있습니다.

참고


posted at 2019/06/03 13:35