[Kubernetes in Google Cloud] Lab3) Orchestrating the Cloud with Kubernetes

Speedwell🍀·2022년 7월 18일
0
post-thumbnail

실습 링크

Overview

In this lab

  • GKE을 사용하여 완전한 Kubernetes 클러스터를 provision

  • kubectl을 사용하여 Docker 컨테이너를 배포/관리

  • Kubernetes의 배포와 서비스를 사용하여 어플리케이션을 microservices로 분할


Monolithic vs. Microservice

Monolithic Architecture

  • 하나의 서버에 다양한 기능이 위치해있는 구조
    ➡ 즉, 하나의 프로젝트에 코드가 모여있고 하나의 파일로 구성됨

    • 컴포넌트들이 하나의 프로젝트에서 관리되고 하나의 공통된 DB를 바라보고 있다.
    • 서로 의존성을 갖고 배포된다.
  • 👍장점

    • 과거에 대부분의 서비스가 이 구조였기 때문에 다양한 레퍼런스 존재
    • 인프라의 구성과 운용 간편
    • 테스트 및 배포 파이프라인 구성이 쉬움
    • 어떤 기능(서비스)이든지 개발되어 있는 환경이 같아서 복잡하지 않음
    • End-to-End 테스트 용이 (Microservice는 테스트에 필요한 서비스들을 모두 동작시켜야 함
  • 👎단점

    • 서비스간에 서로 의존성이 존재하기 때문에 시스템의 일부만 수정하더라도 전체 어플리케이션의 Build, Test, Packaging 과정을 거쳐야 함
      ➡ 작은 수정사항이더라도 전체를 다시 빌드하고 배포
    • 한 프로젝트의 크기가 너무 커서 어플리케이션 구동시간, 빌드/배포에 오랜 시간
    • 많은 양의 코드가 몰려있어 보기 어렵고, 유지보수도 어려움
    • 일부분의 오류가 전체에 영향
    • 기능별로 알맞는 기술, 언어, 프레임워크 선택하기 어려움

Microservice Architecture

  • 👍장점
    • 어플리케이션을 구성하는 서비스 구성요소들이 모두 컨테이너에 의해서 나눠지기 때문에 최소한의 의존성을 가진다.
      ➡ 새로 추가되거나 수정사항이 있는 microservice만 빠르게 빌드/배포 가능
    • 기능별로 microservice를 개발하고, 작업 할당을 서비스 단위로 하면 개발자가 해당 부분을 온전히 이해 가능
    • 일부분의 오류가 있으면 해당 기능에만 오류가 발생
      ➡ 빠른 수정 및 정상화 가능
  • 👎단점
    • 위의 그림에서도 볼 수 있듯이, 구축하는 것이 어려움
      • Monolith는 하나의 프로젝트에서 서로 내부적으로 통신
      • but, Microservice는 여러 프로젝트로 나뉘어 해당 프로젝트끼리 통신을 해야하는 구조이기 때문에 설정에 대한 서버를 따로 둘 정도로 복잡하게 구성
        ➡ 통신관련 오류가 Monolith보다 잦음
    • 관리가 어려움
      • 작은 여러 서비스들이 분산되어 있기 때문에 모니터링이 어려움
    • 테스트가 Monolith보다 불편

참고)
1
2





Kubernetest는 어플리케이션에 중점!
이번 lab에서는 app이라는 예제 어플리케이션을 사용!

Note) App은 Github에서 호스팅되면 12요소 예시 어플리케이션 제공
이번 lab에서는 다음의 Docker 이미지를 다룬다.

  • kelseyhightower/monolith - monolith는 auth 및 hello 서비스 포함
  • kelseyhightower/auth - auth microservice로, 인증된 사용자를 위한 JWT 생성

    JWT(JSON Web Token): 유저를 인증하고 식별하기 위한 토큰(Token)기반 인증 참고

  • kelseyhightower/hello - hello microservice로, 인증된 사용자를 안내
  • ngnix - auth 및 hello 서비스의 프론트앤드

    nginx: 동시접속 처리에 특화된 웹 서버 프로그램


Kubernetes

  • kubernetes.io에서 사용할 수 있는 오픈소스 프로젝트
  • 다양한 환경에서 실행 가능
    • from laptops to high-available multi-node clusters
    • from public clouds to on-premise deployments
    • from virtual machines to bare metal

이번 Lab에서는 Kubernetes Engine과 같은 managed environment을 사용하여 기본 인프라를 설정하기보다는 Kubernetes를 경험하는 데 집중해보자!





실습 시작 전에 개요에서 설정 및 요구사항까지 완료된 상태여야 한다!


Google Kubernetes Engine

  1. 영역 설정
    $ gcloud config set compute/zone us-central1-b

  1. 이번 Lab에 사용할 클러스터 시작
    $ gcloud container clusters create io

    (Kubernetes Engine이 백그라운드에서 몇몇 가상 머신을 프로비저닝하고 있으므로 클러스터를 만드는 데 다소 시간 걸림)

Task 1) Get the sample code

  • Github 저장소 clone
    $ gsutil cp -r gs://spls/gsp021/* .

  • 실습에 필요한 디렉토리로 변경
    $ cd orchestrate-with-kubernetes/kubernetes

  • 파일을 나열하여 작업 중인 파일 확인
    $ ls




Task 2) Quick Kubernetes Demo

Kubernetes를 시작하는 가장 쉬운 방법은 kubectl create 명령어를 사용하는 것!

  1. kubectl create을 사용하여 nginx 컨테이너의 단일 인스턴스 실행
    $ kubectl create deployment nginx --image=nginx:1.10.0

    Kubernetes가 배포를 생성했다! (배포에 대한 자세한 내용은 추후에)
    ➡️ 배포는 pods를 작동하게 하고, pods가 실행하는 노드가 fail해도 계속해서 작동하게 한다.

Kubernetes에서 모든 컨테이너는 pod에서 실행된다.


  1. 실행 중인 nginx 컨테이너 확인
    $ kubectl get pods

  1. nginx 컨테이너가 실행되면 kubectl expose 명령어를 사용하여 Kubernetes 외부로 노출시킬 수 있음
    $ kubectl expose deployment nginx --port 80 --type LoadBalancer

    • Kubernetes가 백그라운드에서 공개 IP 주소가 첨부된 외부 부하 분산기를 생성
      • 이 공개 IP 주소를 조회하는 모든 클라이언트는 서비스 백그라운드에 있는 포드로 라우팅됨
        (이 경우엔 nginx 포드로 라우팅됨)

  1. 서비스 나열
    $ kubectl get services
    • 서비스를 위해 External IP 필드가 채워지는 데 시간 소요되므로 비어있다면 명령어 재실행

  1. 원격으로 Nginx 컨테이너 조회
    $ curl http://<External IP>:80

Kubernetes는 kubectl 실행 및 노출 명령어로 바로 사용할 수 있는 간편한 워크플로 지원




Task 3) Pods

Kubernetes의 핵심은 Pod

Pod는 1개 이상의 컨테이너가 포함된 모음
일반적으로 상호 의존성이 높은 컨테이너가 여러 개 있으면 이를 하나의 Pod에 패키징


위의 pod에 포함된 것

  • monolith 컨테이너
  • nginx 컨테이너
  • volumes
    • pod가 존재하는 한 계속해서 존재하는 데이터 디스크
    • pod에 포함된 컨테이너에 의해 사용될 수 있음

pod는 콘텐츠에 공유된 네임스페이스 제공
➡ 즉, 이 예시의 포드 안에 있는 2개의 컨테이너는 서로 통신 가능하며, 첨부된 volumes도 공유

pod는 네트워크 네임스페이스도 공유
➡ 즉, pod는 IP 주소를 1개씩 소유




Task 4) Creating pods

pod는 pod 구성(configuration) 파일을 사용하여 생성 가능!

  1. monolith pod 구성 파일을 살펴보자
    $ cat pods/monolith.yaml
    • pod가 1개의 monolith 컨테이너로 구성됨
    • 시작할 때 컨테이너로 몇 가지 인수가 전달됨
    • HTTP 트랙픽용 port 80 개방됨

  1. monolith pod 생성
    $ kubectl create -f pods/monolith.yaml

  1. 기본 네임스페이스에서 실행 중인 모든 pods 나열
    $ kubectl get pods

    (monolith pod가 작동하는 데 시간 소요. 이를 수행하기 위해 Docker Hub에서 monolith 컨테이너 이미지 가져와야 하기 때문)

  1. pod가 실행되면 monolith pod 포드에 대해 자세히 알아보자.
    $ kubectl describe pods monolith

    • pod IP 주소 및 이벤트 로그를 포함한 monolith pod에 관한 여러 정보가 표시됨
      ➡ 이 정보는 문제해결 시 유용하게 사용

Kubernetes를 사용하면

  • configuration file에 pod에 관해 설명하여 간편하게 pod 생성 가능!
  • pod 가 실행 중일 때 정보를 쉽게 확인 가능!

➡ 이제 deployment에 필요한 모든 pods를 생성 가능!




Task 5) Interacting with pods

pod에는 기본적으로 비공개 IP 주소가 부여되며, 클러스터 밖에서는 접근 불가.
kubectl port-forward 명령어를 통해 local port를 monolith pod 안의 port로 mapping


(여기서부터 port 간 통신을 설정하기 위해 여러 Cloud Shell 탭 사용)

  1. 두 번째 터미널에서 port 전달 설정
    $ kubectl port-forward monolith 10080:80

  1. 첫 번째 터미널에서 pod와 통신 시작
    $ curl http://127.0.0.1:10080

  1. Error❗) 보안이 설정된 endpoint 조회
    $ curl http://127.0.0.1:10080/secure

    ➡ monolith에서 다시 인증 토큰을 얻기 위해 로그인 시도
    $ curl -u user http://127.0.0.1:10080/login
    비밀번호는 'password'

    로그인하여 JWT 토큰이 출력됨

  1. 토큰을 위한 환경 변수 생성
    (Cloud Shell 은 긴 문자열을 제대로 복사하지 못하기 때문)
    $ TOKEN=$(curl http://127.0.0.1:10080/login -u user|jq -r '.token'

  1. 토큰을 복사 후, 이 토큰으로 보안이 설정된 endpoint 조회
    $ curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:10080/secure

    어플리케이션으로부터 모두 제대로 작동한다는 응답이 전송될 것

  1. monolith pod의 로그를 확인해보자.
    $ kubectl logs monolith

  1. 세 번째 터미널에서 실시간 logs steram을 가져오자.
    $ kubectl logs -f monolith

  1. 첫 번째 터미널에서 curl을 사용하여 monolith pod와 상호작용했다면, 세 번째 터미널에서 로그가 업데이트 되는 것을 확인 가능
    $ curl http://127.0.0.1:10080


  1. monolith pod의 대화형 셸 실행
    📌 이는 컨테이너 내부에서 문제 해결 시 유용
    $ kubectl exec monolith --stdin --tty -c monolith /bin/sh
    • 예를 들어 monolith 컨테이너에 셸이 있으면 ping 명령어를 사용하여 외부 연결 테스트 가능!
      $ ping -c 3 google.com
    • 대화형 셸 사용을 완료한 후에는 반드시 로그아웃
      $ exit

pod와의 상호작용은 kubectl 명령을 사용하는 것만큼 쉽다.
원격으로 컨테이너를 조회하거나 로그인 셸이 필요한 경우, Kubernetes가 작업에 필요한 모든 것을 제공!




Task 6) Services

Pod는 영구적으로 지속되지 않는다.
활성 여부 또는 준비 상태 검사 오류와 같은 다양한 이유로 중지되거나 시작될 수 있으며, 이로 인해 문제가 발생한다.

Pod 집합과 통신해야 하는 경우 어떻게?
Pod가 다시 시작되면 IP 주소가 변경될 수 있다.
➡ 이와 같은 상황에서 Services가 유용!
서비스는 pod를 위해 stable한 endpoints 제공

서비스는 labels을 사용하여 어떤 pod에서 작동할지 결정
pod에 label이 정확히 지정되어 있다면 서비스가 이를 자동으로 감지하고 노출시킨다.

서비스가 제공하는 pod 집합에 대한 액세스 수준은 서비스 유형에 따라 다르다.

  • 서비스 3가지 유형
    • ClusterIP(내부)
      • 기본 유형
      • 이 서비스는 클러스터 안에서만 볼 수 있음
    • NodePort
      • 클러스터의 각 노드에 외부에서 액세스 가능한 IP 주소 제공
    • LoadBalancer
      • 클라우드 제공업체로부터 부하 분산기를 추가
      • 서비스에서 유입되는 트래픽을 내부에 있는 노드로 전달

이제 서비스를 생성해보고, label selectors를 사용하여 제한된 pod 집합을 외부에 노출하는 작업을 수행해보자!




Task 7) Creating a service

서비스를 생성하기 전, https 트래픽을 처리할 수 있는 보안이 설정된 pod를 생성하자!

현재 디렉터리는 ~/orchestrate-with-kubernetes/kubernetes여야 한다.


  1. monolith service configuration file을 살펴보자.
    $ cat pods/secure-monolith.yaml

  1. 보안이 설정된 monolith pod와 configuration data 생성
    kubectl create secret generic tls-certs --from-file tls/
    kubectl create configmap nginx-proxy-conf --from-file nginx/proxy.conf
    kubectl create -f pods/secure-monolith.yaml

이제 보안이 설정된 pod가 있으니 이를 외부로 노출시키자.
이를 위해 Kubernetes 서비스를 만들어야 한다.

  1. monolith service configuration file을 살펴보자.
    $ cat services/monolith.yaml
    • app: monolith, secure: enabled 라벨이 지정된 pod를 자동으로 찾고 노출시키는 역할을 하는 selector가 있다.
    • 외부 트래픽을 port 31000에서 port 443의 nginx로 전달하기 위해 NodePort를 노출시켜야 한다.

  1. monolith service configuration file에서 monolith service 생성
    $ kubectl create -f services/monolith.yaml

서비스를 노출하기 위해 port 사용
➡ 다른 앱이 서버 중 하나에 port 31000과 연결을 시도하면 port 충돌 발생 가능

일반적으로 port 할당은 Kubernetes가 처리
이번 lab에서는 port를 선택했기 때문에 추후 상태 확인(health checks)을 더 쉽게 설정 가능

  1. 노출된 NodePort의 monolith service에 트래픽을 허용시키자.
    $ gcloud compute firewall-rules create allow-monolith-nodeport \ --allow=tcp:31000
    • firewall rule이 잘 생성되었다면, 31000 port에 TCP traffic이 허용


이제 설정이 완료되었으니 port 전달 없이 클러스터 밖에서 안전한 monolith service를 조회할 수 있다.

  1. 노드 1개의 외부 IP 주소 가져오기.
    $ gcloud compute instances list

  1. ❗Error) 보안이 설정된 monolith service를 조회해보자.
    $ curl -k https://<EXTERNAL-IP>:31000
    • 시간 초과!
      ➡ 라벨 때문에 발생한 문제! 다음 Lab에서 해결



Task 8) Adding labels to pods

현재 monolith service에는 endpoints가 없다.
➡ 이 문제를 해결하기 위한 방법 중 하나는 label query와 함께 kubectl get pods 명령어 사용하는 것


  1. monolith label이 지정되어 실행되는 pod들을 확인해보자.
    $ kubectl get pods -l "app=monolith"

  1. "sercure=enabled"를 추가하면?
    $ kubectl get pods -l "app=monolith,secure=enabled"
    ➡ no results

  1. 보안이 설정된 monolith pod에 누락된 "sercure=enabled"라는 label query를 추가해주자.
    $ kubectl label pods secure-monolith 'secure=enabled'

  1. 라벨이 업데이트 되었는지 확인해보자.
    $ kubectl get pods secure-monolith --show-labels

  1. pod에 정확한 라벨을 지정했으니 monolith service의 endpoint 목록을 확인해보자.
    $ kubectl describe services monolith | grep Endpoints

  1. 노드 중 하나를 조회하여 앞서 확인한 endpoint를 테스트해보자.
    $ gcloud compute instances list curl -k https://<EXTERNAL_IP>:31000

    잘 contact 되어 있다!



Task 9) Deploying applications with Kubernetes


📌 이번 Lab의 목표
: production에 있는 container들을 확장하고 관리하는 것
Deployments가 유용!

  • Deployments는 실행 중인 pod의 개수가 사용자가 명시한 pod의 개수와 동일하게 만드는 declarative(선언적) 방식

👍 Deployments의 주요 이점

  • pod 관리에서 낮은 수준의 세부정보를 추상화

Deployments의 역할

  • 백그라운드에서 Replica(복제본) Sets을 사용하여 pod의 시작 및 중지를 관리
  • pod를 업데이트하거나 확장해야 하는 경우 depoyments가 이를 처리
  • deployments는 또한 어떤 이유로든 pod가 중지되면 재시작을 담당하여 처리

간단한 예를 살펴보자.

pod는 생성 기반 노드의 전체 기간과 연결되어 있다.
위의 예시에서 Node3이 중단되면서 pod도 중단된 걸 볼 수 있다.
직접 새로운 pod를 만들고 이를 위한 노드를 찾는 대신, deployments가 새로운 pod를 만들고 Node2를 실행한 것을 볼 수 있다.
➡ 아주 편리한 방식!


pod와 서비스에 관해 배운 모든 지식을 바탕으로, 이제 deployments를 사용하여 monolith 어플리케이션을 작은 서비스로 분할해보자!




Task 10) Creating deployments

monolith 앱을 3가지 부분으로 나누자.

  • auth: 인증된 사용자를 위한 JWT 토큰 생성
  • hello: 인증된 사용자를 안내
  • frontend - 트래픽을 auth 및 hello 서비스로 전달

각 서비스용 deployments를 만들 준비가 되었다.
auth 및 hello deployments용 내부 서비스와 frontend deployment용 외부 서비스를 정의해보자.
➡ 이렇게 하면 Monolith와 같은 방식으로 microservices와 상호작용 할 수 있으며, 각 서비스를 독립적으로 확장하고 배포 가능


  1. auth deployment configuration file을 살펴보자.
    $ cat deployments/auth.yaml
    • deployment가 replica 1개를 만들며, 여기서는 auth 컨테이너 2.0.0 버전 사용

kubectl create 명령어를 통해 auth deployment를 생성하면, deployment manifest 데이터를 준수하는 pod가 생성된다.
➡ 즉, replica 필드에 명시된 숫자를 변경하여 pod 개수 조정 가능


  1. deployment object를 생성해보자.
    $ kubectl create -f deployments/auth.yaml

  1. auth deployment용 서비스를 만들자.
    $ kubectl create -f services/auth.yaml

  1. hello deployment도 똑같이 생성하고 expose하자.
    $ kubectl create -f deployments/hello.yaml
    $ kubectl create -f services/hello.yaml

  1. frontent deployment도 마찬가지.
    $ kubectl create configmap nginx-frontend-conf --from-file=nginx/frontend.conf
    ➡ frontend를 만들기 위해 컨테이너에 구성 데이터를 보관하기 위한 단계
    $ kubectl create -f deployments/frontend.yaml
    $ kubectl create -f services/frontend.yaml

  1. frontend와 상호작용해보자.
    $ kubectl get services frontend

    $ curl -k https://<EXTERNAL-IP>
    ➡ hello 응답!

0개의 댓글