[프로그래머스] 웹 개발 파이프라인 구축(2)

Lina Hongbi Ko·2024년 12월 3일
0

Programmers_BootCamp

목록 보기
68/76
post-thumbnail

2024년 12월 3일

✏️ 쿠버네티스

  • 마이크로서비스 아키텍처

    • 응용 시스템 개발 및 구성을 위한 아키텍처 스타일의 하나
    • 이에 비교하여 전통적인 방식의 아키텍처를 모놀리식(monolithic) 아키텍처라고 부르기도함
    • 어플리케이션이 서비스 모음으로 개발되어 각 마이크로서비스는 특정한 기능을 수용하고 개발 작업을 처리, 이 서비스들이 서로 연결되어 전체 응용을 구성

  • 컨테이너 인프라 환경의 적용

    • 컨테이너 모델은 마이크로 서비스를 구현하기에 적합
  • 쿠버네티스(Kubernetes)란

    • 쿠버네스 아주 도움 되는 글 :
      https://velog.io/@holicme7/K8s-쿠버네티스란-무엇인가

      https://jibinary.tistory.com/82#google_vignette

    • 줄여서 k8s 라고 표기하는 것을 자주 보게 됨

    • 컨테이너 오케스트레이션 솔루션

      • 다수의 컨테이너들을 관리하면서 → 컨테이너들의 관리를 자동화할 도구
      • 자동 배포, 배포된 컨테이너의 동작 보증, 부하에 따른 동적 확장 등의 기능 담당
    • 도커와 잘 어울리는 실행 환경 구성 도구

      • 도커 컨테이너들을 클러스터 내에 실행하고 관리하는데 적합
      • 지속적 통합과 인도 (CI/CD)에 유효하게 적용할 수 있음
      • 컨테이너는 포드 (pod) 라고 불리는 k8s 오브젝트와 연관하여 실행 (포드 위에서 실행한다고 대강 표현)
    • k8s 클러스터

    • k8s 클러스터의 구성 요소

      • 클러스터는 하나 이상의 노드(들)로 구성됨

      • 마스터 노드 (컨트롤 플레인)

        • kubectl(반드시 마스터 노드에 있어야 하는 것은 아님)
        • API 서버, etcd(설정 저장) - 클러스터의 중심 역할을 하는 구성요소들
        • 컨트롤 매니저, 스케줄러
      • 워커 노드

        • 컨테이너 런타임(CRI; Container Runtime Interface) - 포드를 이루는 컨테이너의 실행을 담당
        • kubelet - 포드의 구성 내용을 받아 CRI에 전달하고 컨테이너들의 동작 상태를 모니터링
      • 포드(Pod)와 컨테이너(Container)

    • k8s가 제공하는 기능

      • 컨테이너 밸런싱 (container balancing)

        • 포드의 부하 균등화를 수행 - 몇 개의 응용을 복제할 것인지를 알려주면 나머지는 k8s가 처리
      • 트래픽 로드 밸런싱 (traffic load balancing)

        • 응용의 복제본이 두 이상 있다면 k8s가 트래픽 부하 균등화를 수행하여 클러스터 내부에 적절히 분배
      • 동적 수평 스케일링 (HPA; Horizontal Pod Autoscaling)

        • 인스턴스 수를 동적으로 확장하거나 감축하여 동적 요구사항에 대응하면서 시스템 자원을 효율적으로 활용
      • 오류 복구 (error recovery)

        • 포드와 노드를 지속적으로 모니터링하고 장애가 발생하면 새 포드를 실행하여 지정된 복제본의 수를 유지
      • 롤링 업데이트 (rolling update)

        • 지연 시간을 적용하고 순차적으로 업데이트 배포함으로써 문제가 발생하더라도 서비스를 정상 유지할 수 있음
      • 스토리지 오케스트레이션 (storage orchestration)

        • 원하는 응용에 다양한 스토리지 시스템(Amazon EBS, Google GCE Persistent Disk 등)을 마운트할 수 있음
      • 서비스 디스커버리 (service discovery)

        • 태생적으로 수명이 짧은 포드의 동적 성질을 관리하기 위해 자체 DNS 기반으로 서비스를 동적 바인딩 할 수 있는 기능 제공
    • k8s Pod의 생명 주기 (Life Cycle)

      • kubectl을 통해 API 서버에 포드의 생성을 요청

        • (업데이트가 있을때마다) API 서버는 etcd에 기록하고 클러스터의 상태를 최신으로 유지(하려고함)
      • 컨트롤러 매니저는 포드를 생성하고, 이 상태를 API 서버에 전달

        • 아직 어떤 워커 노드에 포드를 적용할지는 결정하지 않은 상태
      • 스케줄러는 포드가 생성되었다는 정보를 인지하고, 이 포드를 어떤 워커 노드에 적용할지를 결정해서 해당 노드에 포드의 실행을 요청

      • 해당 노드의 kubelet이 CRI에 요청하여 포드가 만들어지고 사용 가능한 상태가 됨

      • k8s는 절차적인 구조가 아닌 선언적인 구조를 가지고 있음

        • 각 요소가 추구하는 상태 (desired state)를 선언하면 현재 상태 (current state)와 비교하고 지속적으로 맞추어 가려고 노력하는 구조
    • k8s 오브젝트들

      • 기본 오브젝트

        • Pod - 한 개 이상의 컨테이너로 단일 목적의 일을 하기 위해서 모인 단위

          • 독립적인 공간과 사용 가능한 IP를 가지고 있음. 언제든지 죽을 수 있음
        • Namespace - k8s 클러스터에서 사용되는 리소스들을 구분해 관리하는 그룹

        • Volume - 포드가 생성될 때 포드에서 사용할 수 있는 디렉토리를 제공

        • Service - 유동적인 포드들에 대한 접속을 안정적으로 유지하도록 클러스터 내 / 외부에 연결하는 역할

      • 디플로이먼트(Deployment)

        • 기본 오브젝트들을 보다 효율적으로 작도알 수 있도록 조합하고 추가로 구현한 것

        • 레플리카셋(replicaset) 오브젝트를 합쳐 놓은 형태로 단순하게 생각할 수 있음

    • k8s 인프라 구축

      • 로컬 환경

        • kubeadm, docker desktop 등을 설치, 운용함으로써 로컬 환경에 간단한 클러스터 구성 가능
        • 개발 단계에서의 테스드 등에 이용
      • Public clouds

        • Amazon의 AWS EKS (Elastic Kubernetes Services)
        • GCP (Google Cloud Platform)의 GKE(Google Kubernetes Engine)
        • Microsoft의 AKS (Azuer Kubernetes Service)
      • On-prem 설치

        • SUSE 의 Rancher
        • RedHat의 Openshift
    • 정리 : container < pod < node(마스터노드-컨트롤플레인, 워커노드-컴퓨팅머신) < cluster

✏️ 쿠버네티스 기본 사용법

  • 계획

    • k8s 클러스터에 어떠한 것을 지시할 수 있는 지 살펴보자

      • 포드의 생성과 컨테이너 실행
      • 디플로이먼트를 이용하여 동일한 기능을 하는 포드의 레플리카셋(복사본)을 실행
      • 클러스터 외부로부터 접근이 가능하도록 서비스 실행
      • 생성된 (현재 관리되고 있는) k8s 오브젝트들 삭제
    • k8s 클러스터의 현재 상태를 조회하는 방법 알아보기

    • 오브젝트 스펙을 작성하는 기초를 익히고 실습하기

  • 실습 시작

  • 노드와 포드 정보 조회

    • kubectl get nodes
    • kubectl get pods
    • 옵션 “o -wide”
  • 정말 아무런 포드도 없는 것일까?

    • kubectl get pods —all -namespaces
    • 쿠버네티스 운용에 필요한 포드들을 확인할 수 있음
  • 컨테이너 이미지를 이용한 포드 생성

    • kubectl run <포드 이름> —image=<이미지 지정>
      • kubectl run nginx-pod —image=nginx
      • kubectl get pods (STATUS : ContainerCreating)
      • kubectl get pods -o wide (STATUS: Running / IP: 클러스터 내에서의 ip주소 / NODE : docker-desktop에서 실행되는 것 알 수 있음)
  • 레플리카셋 복사본 만들기

    • 디플로이먼트를 이용해야함

      • Deployment

        • 응용의 배포를 위하여 많이 이용되는 k8s의 오브젝트 형태
        • 동일한 모습의 포드들의 복제본 모음인 레플리카셋(replicaset)을 이용하는 것이 일반적
        • 단순한 레플리카셋에 비하여 동적 업데이트 및 롤백, 배포 버전의 관리 등이 유연하여 응용의 배포에 널리 이용됨
        • 보통은 상태가 없는 (stateless) 응용의 배포에 이용
          • (기억하자) 포드는 언제라도 사멸할 수 있음
      • 동작 방식

        • 디플로이먼트의 상태를 선언하면 k8s가 동적으로 의도된 상태(desired state)가 되도록 레플리카셋을 관리
    • 디플로이먼트 선언

      • kubectl create deployment dpy-nginx(디프로이먼트이름) --image=nginx
    • 디플로이먼트 상세 조회

      • kubectl describe deployment dpy-nginx
    • 레플리카셋 생성 (포드 늘리기)

      • kubectl scale deployment dpy-nginx --replicas=3
        (1개 → 3개로 늘어난 것 확인할 수 있음 & 각 포드의 IP주소도 다름)

    • 디플로이먼트 조회

      • kubectl get deployment
        (READY 상태 3개인 것 확인)

  • 클러스터 외부로부터 접근이 가능하도록 서비스 실행

    • k8s 서비스 (service) 이용해야함

      • 클러스터 내부의 포드에 의하여 실행되는 응용을 외부에 접근 가능하도록 노출하는 기능을 하는 오브젝트
    • 노출하는 대상

      • 특정 포드 (또는 포드들의 집합)에서 실행하는 컨테이너의 특정 포트
    • 서비스의 서로 다른 형태들

      • ClusterIP
      • NodePort → 이 서비스로 실습 예정
      • LoadBalancer
      • ExternalName
    • 서비스(NodePort)를 통해 노출

      • kubectl expose pod nginx-pod --type=NodePort --name=pod-sve --port=80
        (nginx-pod 포드에 있는 모든 컨테이너가(현재는 한개이지만) 웹서비스 http의 포트번호 80번으로 노출 )

      • kubectl get svc
        (서비스 확인)

      • curl localhost:31444 (서비스를 통한 특정한 포트번호를 통해 포드 노출시킨것 확인 )

      • kubectl expose deployment dpy-nginx --type=NodePort --name=dpy-svc --port=80 (이번엔 디플로이먼트 노출)

      • kubectl get services (서비스 확인)

      • curl localhost:30804 (디플로이먼트 확인 - 위와 같은 결과 나오는 것 확인)

    • 포드 오브젝트 삭제

      • kubectl delete service pod-sve
    • 서비스 오브젝트 삭제

      • kubectl delete service dpy-svc
        (서비스 오브젝트는 없으나 디플로이먼트와 포드들은 여전히 그대로임 & 아까 로컬호스트 포트번호로 접속 불가능)
    • 포드 삭제

      • kubectl delete pod nginx-pod
        (역시 아까 로컬호스트 포트번호로 접속 불가능해짐)
    • 디플로이먼트의 생성에 의하여 만들어진 포드 삭제(포드 삭제하려고 시도했지만, 디플로이먼트의 선언 상태에 맞도록 다른 포드가 생성되어서 세 개의 포드를 유지시킴)

      • kubectl delete deployment dpy-nginx
        (디플로이먼트 삭제 → 포드 확인하면 아무것도 없는 것 확인할 수 있음)

  • 매니페스트 (Manifest)

    • k8s 오브젝트에 대한 명세를 파일로 기록한 것

      • YAML(Yet Another Markup Language 또는 YAML Ain’t Markup Lnaguage) 형태를 이용
    • 파일에 각 오브젝트에 의도하는 상태 (desired state)를 기술

      • 이것을 오브젝트 스펙(obejct spec)이라고 부름
    • 이 파일을 이용하여

      • 오브젝트를 생성할 수 있고
      • (파일의 내용을 변경하여) 오브젝트의 상태를 변경할 수 있음
        • 물론, 파일의 내용을 변경하지 않고 다른 파일을 이용하여 오브젝트 상태를 변경하는 것도 가능
    • 자동화가 필요한 환경에서 (당연히) 명령어 라인에 일일이 입력하는 것보다 많이 이용됨

    • 디플로이먼트의 오브젝트 스펙

    • 서비스의 오브젝트 스펙

  • 매니페이스트를 이용한 오브젝트 생성

    • kubectl apply -f <매니페스트 파일>
      • kubectl create -f 를 이용할 수도 있으나 위의 명령이 더 널리 이용됨

✏️ 쿠버네티스를 이용한 서비스 운용

  • 계획

    • 반복실습과 k8s 클러스터에 배포된 응용의 동작 보증 관찰

    • 간단한 테스트용 flask 웹 응용을 만들고 이것을 nginx 위에 쌓아 도커 이미지 만들기

    • 만들어진 이미지를 이용한 컨테이너를 실행하고 서비스를 노출하도록 매니페스트 작성

    • 이 응용을 (수동으로) k8s 클러스터에 배포하고 예외상황에 대한 k8s의 대처 방식 관측

      • 포드가 사멸하는 경우
      • 컨테이너 실행에 문제가 생기는 경우
  • 실습 - 웹 서버 만들기

  • 웹 서버 만들기

    • 서버 구성 준비

    • 도커 이미지 구성 (컨테이너 설계)

    • 도커 이미지 작성

    • 이미지 태그하고 리포지토리에 푸시

    • 매니페스트 작성



    • 테스트 응용의 수동 배포

      • deployment.yaml에 지정된 대로 포드 생성해서 컨테이너 실행
        • kubectl apply -f deployment.yaml
        • kubectl get deployments (포드의 이름들과 IP주소들을 눈여겨보자)

    • 서비스 생성

      • kubectl apply -f service.yaml
      • 노출된 포트번호로 응답 확인하기
        • curl localhost:30000
      • 그런데 curl localhost:30000 을 계속 여러번 입력해서 확인하면 포드의 이름과 IP주소가 바뀌는 것을 볼 수 있음
        • 왜일까?
          • 쿠버네티스가 부하 균등화를 위해 동일한 기능을하는 똑같은 모습의 포드들(레플리카셋)을 번갈아 가며 이용하는 것
  • 실습 - 주기적인 요청 테스트

  • 주기적인 요청을 이용해 테스트

    • 요청을 반복하는 스크립트 만들기

    • 테스트 준비

    • deployment.yaml replicas: 1로 바꾸고
      • kubectl apply -f deployment.yaml 입력 → 레플리카셋 1로 줄어든것 확인할 수 있음 & curl 계속 실행해도 같은 포드인것 확인 가능 & check.sh 실행해도 같은 포드가 나오는 것 확인할 수 있음


  • 실습 - 포드가 사멸하는 경우 테스트

    • check.sh이 계속 실행하는 상태에서 포드를 사멸했을때 STAUTS가 Terminatng되고 새로운 포드가 생성된 것을 볼 수 있다. 그리고 deployment에는 하나로 존재하는 것을 확인할 수 있음

    • 디플로이먼트의 상태 유지

  • 실습 - 컨테이너에 오류 발생 테스트

    • check.sh이 계속 실행되는데 컨테이너쉘에 접속해서 컨테이너를 죽이면 아래의 스크린샷처럼 잠시 멈추는 구간이 발생하고 다시 쿠버네티스가 다시 시작시키는 것을 확인할 수 있다

    • 포드의 동작 보증

✏️ 포드의 업데이트와 복구

  • 소프트웨어의 업데이트가 발생함에 따라 (매번 새로 배포하는 것이 아니라) 동적 업데이트 필요

    • 여기에서는 수동(kubectl)으로 업데이트 적용하는 실습을 통해 k8s가 어떻게 업데이트를 수행하는지 관찰
  • 소프트웨어의 업데이트는 실패할수 있으므로, 빠르고 유연한 복구는 필수 기능

    • 업데이트 자체가 실패하는 경우 - 이번 강의의 실습에서 복구(rollback)하는 내용 포함
    • 새 버전의 소프트웨어가 오동작하는 경우 - 가능한 한 발생하지 않도록 (어떻게?) 해야 하겠으나, 만약 발생하는 경우에는 (이 확률을 0으로 만드는 것은 불가능) 민첩한 복구 조치 필요
  • 실습 - 롤아웃 정보의 열람

    • 롤아웃 정보의 열람

    • —record 붙여서 다시 실행(nginx 버전 1.17.0으로 수정 후)
      • —record는 deprecated 옵션임 → 나중에는 없어짐

  • 실습 - 배포 이력의 기록: kubectl annotate

    • 이미지 업데이트 성공 및 annotate 남기기



    • 이미지 업데이트 실패 (없는 버전의 이미지로 바꿈 → 실패한 이력 볼 수 있음)

    • 마지막상태로 되돌리기 (kubectl rollout undo deployment dpy-nginx)
  • 실습 - 특정시점으로 디플로이먼트 복구하기

    • kubectl rollout undo deployment <디플로이먼트> —to-revision=<리비전 번호>
    • 특정 리비전으로 복구, 확인

      (나중에 해보자)

✏️ 쿠버네티스 서비스와 볼륨

  • 서비스

    • 클러스터 외부에서 클러스터에 접속하는 방법

      • 클러스터 내부에서 동작하는 기능을 외부로 노출하는 것을 서비스라고 부름
    • 서로 다른 서비스의 종류

      • 클러스터 IP (ClusterIP)
      • 노드포트 (NodePort)
      • 로드밸런서 (LoadBalancer)
      • 인그레스 (Ingress)
    • 클러스터 IP

      • 클러스터 내부에서만 접근할 수 있는 IP를 할당
      • 포트 포워딩(port forwarding) 또는 프록시 (proxy)를 통해 클러스터 외부로부터 접근 가능
      • 테스트, 디버깅 등의 목적에 제한적으로 이용

    • 노드포트

      • 동작 방식
        • 모든 워커 노드의 특정 포트 (NodePort)를 열고 여기로 오는 모든 요청을 노드포트 서비스에 전달
        • 노포트 서비스는 해당 요청을 처리할 수 있는 포드로 요청을 전달
        • 우리가 앞선 실습에서 포드들(디플로이먼트에 속한)이 제공하는 웹 서비스를 클러스터 외부로 노출하기 위해서 적용해 보았던 방법

    • 로드밸런서

      • 클러스터 외부의 로드밸런서(public cloud들 제공)를 이용하여 부하 균등화 수행
      • 노드포트와 달리 특정 노드가 접근 불가한 경우에도 서비스 제공 가능
    • 인그레스

  • 동적 수평 오토스케일링

    • HPA(Horizontal Pod Autoscaler)

      • 부하량에 따라 디플로이먼트의 포드 수를 유동적으로 관리하는 k8s의 기능
        • (보통의 경우) 고려되는 부하량: CPU 및 메모리 사용량
      • 메트릭스 서버(metrics server)로부터 부하 계측값을 전달받아 동일한 기능을 제공하는 포드의 수를 동적으로 조절
    • 스케일링 기준이 되는 값과 최소/최대 포드의 수를 지정

  • 실습 - 응용배포, 오토스케일러 설정

    • 오토스케일러 설정
      • kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
    • 부하 걸기
    • 실습했을 때 내 컴퓨터에서 포드들은 증가하지 않았다. 그래도 이 실습의 목적은 알았음! → 부하가 걸리면 자동으로 포드들을 늘리고 부하가 없으면 포드들이 줄어듦!
    • 실시간 scaling 관찰 명령어 : kubectl get hpa php-pache —watch
    • cpu할당량 확인 명령어 : kubectl get hpa
  • 볼륨

    • k8s는 클러스터 내에서 이용할 수 있는 저장장치(storage)의 추상화된 객체로 볼륨을 정의

    • PV(Persistent Volume)

      • 클러스터 내에 존재하는 스토리지를 추상화한것
      • 클러스터 내의 노드에 존재하는 물리적 저장장치를 이용할 수도 있으며, 다양한 원격 저장소 및 클라우드 서비스들도 이용할 수 있음
    • PVC(Persistent Volume Claim)

      • (사용자에 의한) PV를 이용하기 위한 요청
      • Pod : Node = PVC : PV
        • node: 작업을 실행할 수 있는 컴퓨터가 있어야 pod:볼륨을 이용할 수 있는 개념
      • 저장 공간의 크기와 접근 모드 (읽기/쓰기, …)를 지정
  • 볼륨 이용 실습

    • 디렉토리 만들고 파일들 수정

    • pv-volume.yaml

      • 볼륨(pv) 생성 → STATUS : Available인 상태

      • 볼륨클레임(pvc) 생성 → STATUS : Bound인 상태


      • delpoyment.yaml 실행



      • 호스트 객체에서 디렉토리 만들고 원하는 파일 만들어서 볼륨에 원하는 파일이 있는 경로 설정, pv(볼륨)을 만들기 위해 pvc도 생성해주고, deployment.yaml(볼륨 이용하겠다는 디플로이먼트, 서비스) 설정 → 컨테이너에 해당 파일 만들어진 것 확인 할 수 있음
      • 결론은 호스트객체에서 파일 만들고 pv,pvc 만들어주고 delpoyment, service 설정 후 컨테이너에 연결해서 해당 파일 연결해주고 확인함 → 우리가 작성한 파일이 서비스 되고 있음을 확인
        • 볼륨을 마운트해서 호스트 디렉토리의 index.html 파일이 nginx가 실행되고 있는 컨테이너에서 접근할수 있었음을 확인
  • 만약, 컨테이너가 실행하다가 파일이 만들어져서 볼륨에 저장되면?

    -> 컨테이너에서 생성한 파일을 호스트객체의 디렉토리에서도 확인할 수 있었음

  • 용어 정리

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글