Skip to content

Desired State를 중심으로 살펴보는 인프라 환경

Junha edited this page Nov 12, 2023 · 1 revision

https://github.com/f-lab-clone/ticketing-infra/issues/43 이슈로 부터 작성

1. Terraform

Terraform을 통해 Infra as a code를 사용한다

Infra as a code란 무엇인가?

image

https://blog.naver.com/PostView.naver?blogId=banijun37&logNo=221317570780

위와 같이 기존에 Cloud에 모든 Infra는 웹 브라우저를 통해 컨트롤 해야 했다.

image

하지만, IaC 를 사용하면

  • 코드를 통해서 인프라를 관리 가능
  • 쉽게 정의된 인프라의 상태를 공유하고, 버전 관리 가능
  • 즉 Desired State(내가 원하는 최종 상태)만 정의하면 된다.

Terraform은?

  • IaC Tool로써 다양한 인프라 프로바이더(AWS, GCP 등)을 지원한다.
  • AWS에 존재하는 다양한 API를 호출하여 인프라를 관리한다.
  • AWS에 자체적인 CLI 도구등이 존재하나, 테라폼을 사용했다.

Desired State

IMG_1917

출처

IMG_1918

출처

Infra 관점에서 Desired State은?

Backend Application을 실행하기 위한 컴퓨팅 머신 1대 (=> AWS에서는 EC2)
DBMS를 위한 컴퓨팅 머신 1대 (=> AWS에서는 RDS)

과거의 Infra 생성 방식과 IaC를 통한 생성 방식을 비교해보자.

  • 과거의 생성 방식은 Desired State(최종 상태)에 도달하기 위해 웹을 통해 step-by-step 버튼을 눌러야 했다.
  • 하지만 IaC 도구를 통해 Desired State를 정의(= tf 소스코드)하고, apply하는 것 만으로, 해당 툴이 상태에 도달하는 것을 보장해준다.

Desired State는 해당 문서 전체를 관통하는 주제이다.

왜 테라폼을 사용했는가?

  1. IaC의 장점을 모두 적용한다.
  2. 학습의 관점에서 생각해보자, 인프라를 배울때는 많은 생성과 삭제의 반복이 필요하다. 웹을 통하면 모든 버튼을 반복적으로 클릭해서 생성하고, 삭제할땐 의존성에 따라 하나하나 순서를 지켜서 삭제해야 한다. 하지만 IaC를 사용하면 코드를 수정하고 apply, destroy 명령어를 통해 빠른 학습 사이클이 가능해진다.
  3. 왜 테라폼인가? 가장 유명하고, 자료가 많기 때문에 학습 러닝 커브가 낮다.

그래서 어떻게 생겼나요?

image

https://www.opensourceforu.com/2020/07/the-benefits-of-using-terraform-as-a-tool-for-infrastructure-as-code-iac/

ticketing-infra 레포는 Terraform 소스코드를 저장한다.

버전 관리의 모습

https://github.com/f-lab-clone/ticketing-infra/commits/main

2. Containerization

왜 굳이 도커(컨테이너)를 써야 하나요?를 꼭 읽어보세요. (이 글 대부분의 내용의 출처입니다)

무엇이 문제인가?

문제점

  • 개발 환경과 운영 환경은 다르다. 모든것을 동일하게 맞출 수 없다. "로컬에서는 됬는데 리눅스에서는...."
  • A 서버는 잘 되는데 B 서버는 왜 죽었지?
  • 이렇게 서로 모양이 다른 서버들이 존재하는 상황을 눈송이 서버Snowflakes Server이라고도 합니다. 모든 눈송이의 모양이 다르듯, 서버들도 서로 다른 모습이라는 말이죠.

어떻게 해결할 수 있는가?

image

image

결국 Desired State(최종상태)에 도달하기 위한 step-by-step을 정의하는 것은 너무나도 불편하고, 하나하나의 Step이 각각의 의존성을 가진다.

왜 Container인가?

image

https://kubernetes.io/docs/concepts/overview/

container란? 운영체제 수준의 가상화 기술로 리눅스 커널을 공유하면서 프로세스를 격리된 환경에서 실행하는 기술

  • 높은 이식성(=확장성) 모든 컨테이너는 호스트의 환경이 아닌 독자적인 실행 환경을 가지고 있습니다. 이 환경은 파일(Dockerfile)들로 구성되며, 이미지 형식으로 공유될 수 있습니다. 리눅스 커널을 사용하고 같은 컨테이너 런타임을 사용할 경우 컨테이너의 실행 환경을 공유하고 손쉽게 재현할 수 있습니다.

Docker

도커없이 컨테이너 만들기를 보면 Containerization은 Linux 커널 기술을 바탕으로 하는 것을 알 수 있다. 그렇다면 Docker는 해당 기술을 Wrapping한 Tool이라고 이해할 수 있다.

image

https://dbconvert.com/blog/building-docker-images-for-dbconvert-tools/

image

Docker File - Docker Image를 만들기 위한 명세서

서버 코드화의 장점

  • 서버 제작 과정에 견고함과 유연성을 더할 뿐 아니라
  • 다른 이가 만든 서버를 소프트웨어 사용하듯 가져다 쓸 수 있고
  • 여러 대에 배포할 수 있는 확장성

왜 도커를 써야 하나요?

도커 없이도 배포/운영하고 있는데, 우린 아무 불편을 느끼지 못합니다. 왜 도커를 써야 하죠?

서버 배포와 운영에 도커를 꼭 써야만 하는 건 아닙니다.

하지만 지금 상황에 너무 익숙해져서 문제라고 느끼지 않는 문제는 없을까요? 수평적 확장이 자유롭나요? 서버의 견고함을 보장하면서도 동적으로 바꿀 수 있는 유연함이 존재하나요? 퇴사를 하거나 부서를 옮겨야 해서 다른 이에게 서버 운영 기록을 인계하려면 시간이 얼마나 걸릴까요?

도커가 아니어도 이미 다른 방식으로 문제를 해결할 수 있겠지만, 저에게는 아직까지 도커가 가장 편리한 해결 방법이었습니다.

그래서 어떻게 생겼나요?

image

image

https://github.com/f-lab-clone/ticketing-backend/blob/main/Dockerfile

image

https://devlog-wjdrbs96.tistory.com/318

클래스와 인스턴스로 도커 이해하기

  • 해당 내용은 출처를 참고하라

IMG_1920

도커 파일 == Class file
도커 이미지 == Runtime의 Class Object
도커 컨테이너 == Class의 Instance 
  • Dockerfile은 일종의 Class file과 같다.
  • Dockerfile을 build해서 Image가 만들어졌을때의 image는 runtime의 Class Object이다.
  • Image를 실행했을때 만들어지는 컨테이너(ps)는 Instance이다.

Desired State로 도커 이해하기

도커 파일 == Desired State
도커 이미지 == 도커 파일 + 실행 시점 (Immutable)
도커 컨테이너 == 도커 이미지 + 환경 변수 (mutable)

도커 파일은 Desired State를 기록한 단순한 텍스트 파일이다

이미지는 Dockerfile로 부터 실제로 실행에 필요한 파일, 의존성, 설정값등을 포함하고 있으며, 현재 상태를 가지지 않고 변하지 않는다. (Immutable)

  • 예를들어, Class Source Code로 부터 만들어진 (runtime의) Class Object는 여러 의존관계를 가지며 Instance를 생성(Construct)하듯이, 이미지 또한 실제로 여러 의존성과 파일등을 가지고 (GB, MB 등의 용량) Container를 생성한다.

컨테이너는 Image를 통해 실제로 실행되고 있는 Instance이다.

  • Instnace가 setValue()등을 통해 변경 가능하듯, Container도 변경 가능하다.

3. EKS

왜 Kubernetes가 필요나요?

수 많은 도커 컨테이너를 어떻게 배포하고, 종료하고 관리할 수 있을까? 아래와 같이?

$ docker run A
$ docker run B

....

$ docker delete

아니다. 너무나 많은 리소스가 존재한다.

image

https://www.atlassian.com/ko/microservices/microservices-architecture/kubernetes-vs-docker

그래서 어떻게 생겼나요?

image

https://www.youtube.com/watch?v=y_vy9NVeCzo

image

https://kubernetes.io/ko/docs/concepts/overview/components/

왜 EKS를 사용하나요?

AWS의 Managed Kubernetes 서비스인 EKS를 선택

  • 직접 관리해야 하는 부분을 서비스화 했다. (안정성, 편의성 제공)
  • 특히 Control plane을 직접 관리하지 않아도 된다.
  • 여러 AWS Resource 사용 등에 편의성을 제공한다.

image

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/what-is-eks.html image https://rafay.co/the-kubernetes-current/getting-started-with-amazon-eks/

그외

k8s on EC2 Group을 사용하지 않은 이유? CD: 배포를 위한 환경 세팅 [학습]에서 설명 ECS를 사용하지 않은 이유는? 러닝 커브 차이 EC2 on EKS vs Fortage on EKS? Fortage를 최적화할 수 없기 때문에 EC2 사용

그래서 어떻게 생겼나요?

Terraform을 통해 EKS를 관리

image

https://github.com/f-lab-clone/ticketing-infra/blob/main/src/terraform/eks.tf

Desired State

계속 코드를 통해 Desired State를 선언(declare)하고 적용(apply)하는 것의 반복이다.

IMG_1917

출처

Infra 관점에서는?

  • Terraform 을 통해 Desired State을 선언하고(=tf 파일), apply 한다.

하나의 Process 관점에서는?

  • Docker를 통해 Desired State를 선언하고 (=Dockerfile), build하고, run한다.

하나의 웹서비스를 구성하는 Process들의 관점에서는?

  • Kubernetes를 통해 Desired State를 선언하고 (= yaml 파일), apply한다

IMG_1918

출처

어떻게 Act 하는지는 또는 원하는 상태에 어떻게 도달하는지 신경쓰지 않아도 된다.

우리는 해당 툴이 Desired State도달할 것을 보장한다

  • 위 모든 툴을 사용하는 이유이다.

4. AWS Infra Resource

#37 을 중심으로 AWS에서 사용하는 리소스를 설명한다

image

EKS와 EKS Node 의 차이점은?

image

https://aws.amazon.com/ko/blogs/containers/de-mystifying-cluster-networking-for-amazon-eks-worker-nodes/

Node자원은 EC2와 Fortage로 나눠진다.

  • 또한 남는 EC2를 사용하는 SPOT Instance도 존재한다.

ALB란 무엇인가?

Application Load Balancer의 약자

AWS에서 제공하는 Load Balancer 서비스

image

https://aws.amazon.com/ko/blogs/korea/using-static-ip-addresses-for-application-load-balancers/

NLB와 ALB의 차이는?

  • NLB는 OSI L4 계층
  • ALB는 OSI L7 계층

RDS란 무엇인가?

Relational Database Service

AWS가 제공하는 DB 서비스

  • Kubernetes와 EKS 관계와 비슷하다.
  • Oracle, MySQL 등 여러 DBMS 지원

Bastion Host란?

특수한 목적을 가진 Host (AWS에선 EC2를 사용)

특수한 목적이란?

  • RDS는 Private Network(= Internet 접속이 불가능한 네트워크 환경)에 배치한다.
  • 애플리케이션은 Public Network에 속하기 때문에 인터넷으로 부터 요청을 받을 수 있으며, 같은 Network에 속하는 RDS와 통신할 수 있다.
  • 그렇다면 사용자가 워크벤치(DB Tool)를 통해 DB를 조회하거나 여러 작업을 할려고 하면 어떻게 할까? (적어도 사용자의 작업 컴퓨터는 AWS VPC 안에 없다)

IMG_1922

Bastion Host를 구성한다

  • Bastion Host는 RDS와 같은 Network(VPC)에 속하기 때문에 RDS와 통신 가능 (애플리케이션과 동일하다)
  • 또한 애플리케이션과 동일하게 외부 인터넷으로부터 요청을 받을 수 있다.
  • 다른점은 Bastion Host는 HTTP Request를 받는게아니라, SSH 요청을 받는다

IMG_1923

https://blog.devolutions.net/2017/04/how-to-configure-an-ssh-tunnel-on-putty/

image

SSH 터널링 기술을 사용해 DBMS에게 요청을 전달한다

#25 를 통해 관련 내용 확인 가능

Bastion Host를 사용하는 이유는?

  • 배스천 호스트를 운영하고 있다면, 패스워드가 탈취 당하더라도 공격자가 Target 서버에 대한 권한을 획득 할 수 없다.

그래서 어떻게 생겼나요?

infra

#1

위 모든 자원은 Terraform 을 통해 관리됩니다

5. CD Piepeline

우리가 구현하고자 하는 CD pipeline

1_bmfZlifjlBzqka4heoRg-w

#1

Docker Image Repository 란 무엇인가?

image

https://learn.microsoft.com/en-us/dotnet/architecture/microservices/container-docker-introduction/docker-containers-images-registries

도커 이미지를 관리하는 원격 저장소

ECR은?

Amazon Elastic Container Registry의 약자로, AWS가 제공하는 Service이다.

image

Github처럼 Docker에 저장소로 Docker hub가 존재한다.

  • Docker Hub에는 공식적으로 유지되는 수많은 오픈 소스 컨테이너 이미지들이 존재, 쉽게 활용 가능

github(Docker hub)와 gitlab(ECR)의 차이점을 생각해보면 이해가 쉬울 것 같다.

왜 Docker Image Repository가 필요한가?

만약 Image Repo가 없다면 직접 Dockerfile을 통해 Build & Run 해야한다.

  • 모든 의존성을 설치하고, 처음부터 빌드해야 한다.

불변하는 이미지 파일을 원격에 저장하고, 다운로드함으로 효율적으로 컨테이너를 실행할 수 있다.

Multi-stage-build 를 통해 더더욱 절약이 가능하다

Git Actions를 통한 ECR 업로드

image

ticketing-backend 레포지토리에 설정된 AWS 인증정보

image

https://github.com/f-lab-clone/ticketing-backend/blob/main/.github/workflows/aws-ecr-push.yml

먼저 Backend Repo에 필요한 환경변수를 저장하고, Git actions를 통해 실제로 Push하는것을 볼 수 있다.

image

backend 의 이미지가 ECR에 저장되는 것을 확인할 수 있다. (현재는 main branch에 새로운 commit이 생길때마다 저장한다)

ArgoCD란?

“Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.”

image

https://youtu.be/MeU5_k9ssrs?t=557

image image

https://coffeewhale.com/kubernetes/gitops/argocd/2020/02/10/gitops-argocd/

Git에 Desired State를 정의하면, Cluster가 해당 State에 도달함을 책임진다.

  • 애플리케이션의 배포와 운영에 관련된 모든 요소들을 Git에서 관리(Operation) 한다
  • Git Repo(Desired State)가 달라졌을때, Current State와 비교하여 Sync(Act)한다.

Git ops는 배포(CD) 관점에서의 Desired State를 "Git"에 정의하는 방법론이고, ArgoCD는 Git ops의 구현체이다.

  • ArgoCD를 통해 Git을 사용해 Kubernetes의 Desired State를 정의 할 수 있다.

왜 ArgoCD인가?

ArgoCD는 K8s Cluster안에서 동등하게 실행됨으로써 기존의 Kubernetes 리소스를 사용한다. CD를 위해 별도의 리소스를 사용하지 않아도 된다.

  • 따라서 별도의 시스템을 구축할 필요성이 없어졌다.

그 외

  • 쿠버네티스가 아닌 다른 환경에서는 사용하지 못한다. 혼합환경을 사용하고 있는 곳이라면 Argo CD는 적절하지 않다. (Jenkins 등을 사용해야 한다)
  • Git Service에 장애를 생각해야 한다

그래서 어떻게 생겼나요?

argo-cd-ui-87dce328a7ab3be2d13f7926831068eb

https://jennifersoft.com/ko/blog/tech/2023-08-30-jennifer-kubernetes-3/

image

infra

#1

이제 ArgoCD를 통해 Cluster 안에 자원을 관리함을 알 수 있다.

Pod의 이미지는 ECR에서 가져온다.

ArgoCD는 누가 설치하나요?

image image

Terraform을 통해 설치한다. (Terraform에 Desired State를 정의)

  1. EKS 배포
  2. ArgoCD 설치
  3. applications.yaml 파일 apply
  4. 위 정의된 Desired State(git-repo)대로 ArgoCD가 Cluster 자원을 관리 (해당 Repo에는 backend-pod, redis, alb 등이 선언되어 있다.)

6. Performance Test & Monitoring

성능 테스트란 무엇인가

해당 내용의 출처는 엘리스 CTO가 알려주는 ‘서버 성능 측정 방법’입니다

image

어느 서버가 더 성능이 좋은가?

  1. 10명이 동시에 호출했을 때 1초 안에 모두가 응답을 받음
  2. 100명이 동시에 호출했을 때 10초 안에 모두가 응답을 받음

Latency : 사용자의 입장에서 응답에 걸리는 시간 Throughput: 작업자의 입장에서 시간당 얼마나 처리하는가

테스트 시나리오

10개의 커넥션 5초동안 연결

  • Latency 11.5 ms
  • 종합해서 1초에 885개의 Request 처리

100개의 커넥션을 5초동안 연결

  • Latency 104 ms
  • 1초당 950개의 Request처리

그렇다면 "우리 서버는 동시에 950명이 접속해도 안전합니다"라고 말 할 수 있는가? 이건 그저 "서버가 버틸 수 있을때까지 최대한 Request를 넣어보는 행위"

  • 서버의 한계치를 알 수 있지만, 동시접속자를 몇명까지 받을 수 있냐에 답은 아니다. (각 유저들은 응답 속도가 느려지는 등...)

테스트 시나리오 개선

"100명의 유저가 30초동안 Request를 하는데, 인당 1초에 1번씩 Request를 한다"

  • 집중하는것은, 사람들이 API에서 response를 받는데 얼마나 걸리는가
  • 위 테스트는 얼마나 처리할 수 있고, 그때 Latency가 얼마인가
  • 이번 테스트는 "얼마나 처리할 수 있나"를 고정하고 그때 Latency가 얼마나 빠른가

1초에 100개씩했을때 Latency가 3ms, 10배를했을때 Latency가 1s

  • Request는 10배가 늘어났는데 Latency는 300배 느려졌다

어떻게 개선하는가?

  1. 서버 대수를 늘린다. image image

  2. 코드를 효율화한다.

image

그래서 우리는 어떻게 할 수 있을까?

image

가장 간단하게 무작정 테스트하는 방법

  1. 최대한 요청을 넣고 병목지점을 확인한다
  2. 서버 대수를 최대한 억제하고, 로직을 개선한다.

조금 더 전략적인 방법

  1. 현실적인 성능 측정 지표를 설정하고 성능을 개선한다
  2. 서버 대수를 최대한 억제하고, 로직을 개선한다.
  3. 서버 대수의 증가로 변화하는 처리능력을 측정한다
  4. "성능 기준"을 정하고 Git actions를 통해 테스트 자동화
  5. 서버 구조의 변화를 준다. [우아콘2020] 배달의민족 마이크로서비스 여행기 참고

일단 2번까지 도달했으면... 4번의 경우는 너무 긴 여정이 될 것 같다.

어떻게 성능 테스트 환경을 구성했는가?

더 자세한 정보는 https://github.com/f-lab-clone/ticketing-infra/issues/32#issuecomment-1711245329 를 참고

1. Database를 초기화한다

1

왜 데이터베이스 초기화 작업이 필요한가?

  • 동시실행에 대한 문제점

    • 만약 동시에 성능 테스트가 진행되면 테스트 결과가 오염된다 (예를들어 테스트 당시의 DB CPU Usage 등)
    • 이는 매 테스트마다 모든 자원을 새로 생성/할당하는게 아니면 발생할 수 밖에 없는 문제이다. (비용이슈로 불가능)
    • 다만 동시실행 이슈는 사이드프로젝트 레벨에서 중요하지 않은 문제이기에 고려하지 않는다.
  • 애플리케이션 초기화 문제

    • 동일한 자원으로 어떻게 여러번의 부하 테스트를 진행할것인가? 즉 어떻게 초기화할 것인가?
    • 애플리케이션 리소스와 모니터링 환경 및 데이터는 그대로 유지. 그 외 Stateful 리소스의 Data 초기화
    • 즉 DB를 매 테스트 전후 Clean up 한다. (현재 DB가 유일한 Stateful 리소스)
    • 따라서 리소스의 재생성 없이 테스트 환경 세팅이 가능하다

2. K6를 통한 성능테스트를 진행한다

2

왜 로컬 환경에서 테스트하는가?

  • 고려대상: k6 cloud, aws-ec2-same-vpc, aws-ec2-another-vpc, local
  • 같은 VPC 내부에서는 테스트를 진행하지 않는다. 최대한 사용자의 접속 환경과 유사하게 구성한다.
  • 먼저 Local 환경에서 부하를 만들어내고, 만약 리소스가 부족하다면 K6 Cloud와 ec2-another-vpc(by terraform) 중 고민한다.

3. Grafana 대시보드를 통해 결과를 확인한다

3

프로메테우스란?

image

https://devocean.sk.com/blog/techBoardDetail.do?ID=163266

image > https://gywn.net/2021/07/make-own-query-exporter-with-go/

그라파나란?

image

image

K6 Report

성능테스트 자동화할 필요가 있을까?

즉 성능에 대한 Desired State를 정의할 필요가 있을까?

  • 현재 필요 없다

일단 먼저 성능 최적화를 달성하고 "일정 성능 유지"를 위해 자동화한다

  • thresholds 를 통해 Success/Fail 판단하는 등
  • Git actions 를 통해 자동화 가능

7. 그래서 인프라팀은 무슨일을 하는가?

드디어 인프라팀이 무슨일을 하는가 설명이 가능하다.

필요한 Desired State에 알맞는 툴을 찾고, 사용 방법을 배우고, 작성하고 테스트한다.

  • Terraform을 통해 Infra의 Desired State를 정의
  • kubernetes를 통해 Container의 Desired State를 정의
  • ArgoCD를 통해 배포의 Desired State를 정의 (추후 기술)

그리고 이때 만나는 모든 문제를 해결한다

우리가 느끼고 있는 것

아래 모든 내용의 출처

상상 속 Devops

IMG_1925 IMG_1924

실제 Devpos

IMG_1926 IMG_1927

Production Level Infra를 만드는데 걸리는 시간

IMG_1928 IMG_1931

“24개월? 진짜? 나도 책 읽고, 미디엄에서 글 읽고, EC2도 만들어보고 다 했는데? 그정도는?…”

Reason 1. Yak Shaving (야크털깍기)

“어떤 목적을 달성하기 위해 원래 목적과 전혀 상관없는 일들을 계속해야 하며 그중 마지막 작업"을 의미

예로 소스 품질이 안 좋아서 테스트 코드를 작성하고 자동화된 테스트를 수행해서 품질을 높이려고 Test Framework 을 도입할 수 있습니다.

하지만 보통은 다음과 같이 흘러가는 경우가 많게 됩니다.

  • 프로젝트에서 사용하는 JDK 의 버전이 낮아서 Test Framework 를 지원 안 함
  • JDK 를 높였더니 담당자가 퇴사한 공통 코드에서 뻑이 나서 그걸 수정
  • 구동했더니 WAS 에서 뻑이 나서 원인 파악후 WAS 업그레이드
  • WAS 업그레이드후 상용 3rd party library 에서 문제 발생
  • 3rd party 업체에 기술 지원 요청했더니 처음 보는 현상이라고 본사 연구소에 escalation 했는데 처리까지 몇 달 걸린다고 함.

만약 인프라에 새로운 작업이 생겼고, 진행중에 문제가 생긴다면 나는 결국 “야크털깍기”를 해야 한다

  • “내가 지난 3주동안 뭘 했지? 이건 10분이면 끝날 일인데?…”

Reason 2. The production-grade infra checklist

IMG_1932

  • 모니터링, 배포, 로그 등등…
  • Document, 비용 최적화, Test 작업은 보통 도달하기전에…
Clone this wiki locally