[마이크로서비스] AWS 빌드 및 배포(ELK, EKS) part1 (11)

hyeokjin·2022년 8월 21일
0

microservice

목록 보기
11/13
post-thumbnail

빌드/배포 파이프라인 아키택처

마이크로서비스 빌드/배포 파이프라인 구축과 관련된 부분과 단계를 보자.

빌드/배포 프로세스는 네 가지 핵심 패턴을 기반으로 한다.

  • 지속적 통합/지속적 전달 : 애플리케이션 코드가 커밋되고 배포될 때만 빌드하고 테스트하지 않는다. 즉, 코드가 단위와 통합, 플랫폼 테스트를 통과하면 즉시 다음 환경으로 승격된다. 유일하게 멈출 때는 운영환경에 배포할 때 다.

  • 코드형 인프라스트럭처 : 개발 환경 및 상위 환경에 반영되는 최종 소프트웨어 산출물은 머신 이미지이다. 머신 이미지와 이미지에 설치된 마이크로서비스는 마이크로서비스의 소스 코드가 컴파일 되고 테스트되면 바로 프로비저닝이 된다. 서버가 구축된 후에는 절대 수작업으로 서버를 변경하면 안된다.

  • 불변서버 : 서버 이미지가 생성된 후 프로비저닝 프로세스한 후에는 서버의 구성 및 마이크로서비스를 절대 변경할 수 없다. 변경이 필요하면 서버 프로비저닝 스크립트를 변경하고 새 빌드를 시작해야한다.

파이프라인에서 시작하기 전에 클라우드에 핵심 인프라스트럭처를 설정해보자.

클라우드에 O-stock 핵심 인프라스트럭처 설정

지금까지 도커 컨테이너로 실행되는 단일 가상 머신 이미지 안에서 애플리케이션들을 실행했다.
이제 데이터베이스 서버와 캐싱 서버(레디스)를 도커에서 아마존 클라우드로 변경할 것이다.
그 외 다른 서비스는 모두 아마존 EKS 클러스터의 한 노드에서 도커 컨테이너로 실행 시킨다.

다음 그림을 참고하자

  1. 모든 서비스(O-stock 애플리케이션)는 도커 컨테이너로 배포되며 컨테이너들은 EKS 클러스터의 단일 노드에서 실행 하도록 만든다.
    EKS는 도커 클러스터를 실행하는데 필요한 서버를 구성하고 설정한다.

  2. 아마존 클라우드에 배포하면서 도커 기반의 PostgreSQL 데이터베이스와 레디스 서버 대신에 아마존 RDS와 아마존 ElastiCahe 서비스를 사용한다. 도커에서 Postgres 및 레디스 데이터 저장소를 계속 진행할 수 있지만 클라우드 공급자가 관리하는 것으로 바꿀것이다.

  3. 데스크톱 배포와 달리 서버의 모든 트래픽이 API에 통과해야한다. 아마존의 보안그룹을 사용하여 배포된 EKS 클러스터의 8072 포트 번호만 외부에서 액세스 할 수 있도록 허용한다.

  4. 서비스를 보호하고자 스프링의 OAuth2 서버를 사용한다. 조직 및 라이선싱 서비스에서 액세스 하기 전에 사용자는 인증 서비스로 인증하고 모든 서비스 호출에 유료한 OAuth2 토큰을 제시해야한다.

  5. 카프카 서버를 포함한 모든 서버의 전용 도커 포트는 외부에서 공개적으로 액세스 되지 않는다.
    EKS 컨테이너 내부에서만 해당 포트 액세스가 가능하다.

아래는 진행하고자하는 서비스들의 소스를 참고할 깃헙 주소이다.

https://github.com/hyeokjinON/microservice_study/tree/master/chapter12

AWS 작업을 위한 몇가지 전제 조건

아마존 인프라스트럭처를 설정하라면 다음 설정들이 필요하다

  • 아마존 웹 서비스 계정

  • 웹 브라우저

  • AWS CLI(명령줄 인터페이스) : AWS 서비스를 관리하는 통합 도구

  • kubectl : 쿠버네티스 클러스터와 통신하고 상호 작용할 수 있는 도구

  • IAM Authenticator : 쿠버네티스 클러스터에 대한 인증을 제공하는 도구

  • Eksctl : AWS 계정 내 AWS EKS 클러스터를 관리하고 생성하는 간단한 명령줄 유틸리티

해당 설정관련 내용들은 따로 정리했다. 시작하기 앞서, 아래 링크에서 먼저 설정 및 설치를 진행하자

aws 작업을 위한 몇가지 전제 조건

아마존 RDS를 사용한 PostgreSQL 데이터베이스 생성

AWS 관리 콘솔의 데이터베이스 생성 화면에서 기본 구성을 설정한다.

아래와 같이 생성되었다

아마존에 레디스 클러스터 구축

도커에서 실행 중인 레디스 서버를 아마존 ElastiCahe로 이동하려고 한다. 인메모리 데이터 캐시를 구축할 수 있다.

아래와 같이 생성되었다

O-stcok 과 ELK 배포

일레스틱서치, 로그스태시, 키바나 서비스를 EC2 인스턴스에 배포하고 O-stock 서비스들을 아마존 EKS 컨테이너에 배포한다. EC2 인스턴스는 애플리케이션을 실행할 수 있는 아마존 Elastic Computer Cloud의 가상 서버다.

첫번째 작업으로 아마존 EKS 클러스터에 O-stock을 수동으로 배포를 해보면서, 서비스 배포 매커니즘을 이해 하고 컨테이너에서 실행 중인 배포된 서비스를 확인해보자
(이 장에서는 첫번째 부분만 다룬다)

두번째 작업으로는 빌드/배포 프로세스 전체를 자동화하고 사람의 개입을 제한하는 것이다. 마이크로서비스를 설계, 빌드하고 클라우드에 배포하는 방법을 보여줌으로써 가장 중요한 부분이다.
(다음 챕터에서 진행한다)

ELK EC2 생성

ec2 인스턴스를 생성하려면 다음 단계를 수행한다.

  • 아마존 머신 이미지 선택
  • 인스턴스 타입 선택
  • 구성 세부 정보, 스토리지, 태그에 대한 기본 구성 설정
  • 새 보안 그룹 생성
  • ec2 인스턴스 시작

해당 설정들을 해주면 EC2 대시보드에서 아래와 같이 생성된 것을 볼 수 있다

다음으로 EC2 인스턴스에 접속 설정 및 ELK 스택을 배포하자

ELK 배포는 다음과 같다

  • 접속이 성공되면 EC2 인스턴스 업데이트
  • 도커 설치
  • 도커 컴포즈 설치
  • 도커 실행
  • ELK 서비스가 포함된 docker-compose 파일 실행

(참고로 필자는 WSL2 환경에서 진행을 했다. WSL에서는 키페어의 권한을 변경해도 그룹, 사용자에 대해 적용이 되지 않아 홈 디렉토리에서 수정을 했다)

키 페어와 AWS폴더를 홈경로에 복사하여 EC2를 실행하도록함

-- 깃소스 챕터12의 AWS 폴더 홈경로에 복사해놓기
cp -r  AWS ~/

-- PEM키는 홈경로에 복사(WLS에서 키페어 권한설정 하기위해)
cp elk-service.pem elk-service.pem /~

-- 홈경로 이동
cd ~

-- ssh 접속을 위한 키페어 권한설정
chmod 400 elk-service.pem

-- AWS폴더 EC2에 옮기기 (인스턴스 IPv4 주소기준)
scp -r -i elk-service.pem ./AWS/ ec2-user@13.209.97.168:~

-- EC2(아마존 리눅스 접속, 인스턴스 IPv4 주소기준 접속한다)
ssh -i elk-service.pem  ec2-user@13.209.97.168

접속성공

-- EC2 어플리케이션 업데이트
sudo yum update

-- 도커설치
sudo yum install docker

-- ec2 업데이트 및 도커설치
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

-- 권한설정
sudo chmod +x /usr/local/bin/docker-compose

-- 심볼릭링크설정
sudo ln -s /usr/local/bin/docker-compose  /usr/bin/docker-compose

-- 도커실행
sudo service docker start
 
--백그라운드에서 프로세스 실행
sudo docker-compose -f AWS/EC2/docker-compose.yml up -d

-- docker ps 명령어 권한거부시 권한부여
sudo chmod 666 /var/run/docker.sock
> 참고 : https://newbedev.com/got-permission-denied-while-trying-to-connect-to-the-docker-daemon-socket-at-unix-var-run-docker-sock-get-http-2fvar-2frun-2fdocker-sock-v1-24-images-json-dial-unix-var-run-docker-sock-connect-permission-denied-code-example

설정이 완료되었으면 키바나 접속을 해보자
http://13.209.97.168:5601/

EKS 클러스터 생성

EKS는 AWS에서 쿠버네티스를 실행할 수 있는 아마존 서비스다. 쿠버네티스는 배포, 스케줄링, 컨테이너 생성 및 삭제를 자동화하는 오픈 소스 시스템이다.

쿠버네티스 같은 도구를 사용하면 모든 컨테이너를 더 빠르고 효율적으로 다룰 수 있다.
수백 개의 컨터이너로 전파되는 마이크로서비스와 그 이미지를 업데이트해야 하는 상황에서 쿠버네티스를 사용하면 간단한 명령을 실행하여 쉽게 삭제하고 다시 만들 수 있다.

EKS 클러스터 생성 프로세스는 AWS 관리 콘솔 또는 AWS CLI를 사용하여 수행할 수 있다.

AWS CLI를 사용하여 쿠버네티스 클러스터 생성 및 구성을 시작해보자.

  • 쿠버네티스 클러스터 프로비저닝
  • 마이크로서비스 이미지를 리포지터리로 푸시
  • 마이크로서비스를 수동으로 쿠버네티스 클러스터에 배포

쿠버네티스 클러스터 프로비저닝

AWS CLI로 클러스터 생성

// m4.large EC2 인스턴스 한 개를 작업 노드로 사용하는 쿠버네티스 클러스터(ostock-dev-cluster)를 생성할 수 있다
// EC2 ELK 서비스 생성 마법사에서 선택한 것과 동일한 인스턴스 타입(m4.large)을 사용한다.

eksctl create cluster --name=ostock-dev-cluster --nodes=1 --node-type=m4.large

생성이 잘 되었는지 확인하자

// kubectl 구성 확인
kubectl get svc

// 만약 구성확인시 이렇게 에러나올 시 kubernetes-cli 현재 v1.24.0인 버전으로 업그레이드 해야한다.
Unable to connect to the server: getting credentials: decoding stdout: no kind "ExecCredential" is registered for version "client.authentication.k8s.io/v1alpha1" in scheme "pkg/client/auth/exec/exec.go:62"

// 아래 명령어를 실행하자
// v1alpha1 API에 의존하는 client-go 자격 증명 플러그인 client.authentication.k8s.io/v1alpha1 ExecCredential이 제거되었다.
aws eks update-kubeconfig --region ap-northeast-2 --name ostock-dev-cluster

마이크로서비스 이미지를 리포지터리로 푸시

이 전 챕터 까지는 로컬 머신에서 서비스를 구축했었다.
EKS 클러스터에서 이러한 이미지를 사용하려면 도커 컨테이너 이미지를 컨테이너 리포지터리로 푸시해야 한다.
컨테이너 리포지터리는 생성된 도커 이미지에 대한 메이븐 리포지터리와 같다.
도커 이미지에 태그를 지정하고 업로드하면 다른 프로젝트에서 이미지를 내려받아 사용할 수 있다.

도커 허브 같은 여러 리포지토리가 있지만 아마존 ECR을 사용해보자.

이미지를 컨테이너 레지스트리에 푸시하려면 도커 이미지가 로컬 디렉터리에 있는지 확인해야한다.

// 이미지가 없다면 띄우자. 띄울 이미지들을 스크립트로 만들었다.
#!/bin/bash
mvn clean package
docker build -t ostock/authentication-service:chapter12 --build-arg JAR_FILE=target/authentication-service-chapter12.jar ./authentication-service
docker build -t ostock/configserver:chapter12 --build-arg JAR_FILE=target/configserver-chapter12.jar ./configserver
docker build -t ostock/eurekaserver:chapter12 --build-arg JAR_FILE=target/eurekaserver-chapter12.jar ./eurekaserver
docker build -t ostock/gatewayserver:chapter12 --build-arg JAR_FILE=target/gatewayserver-chapter12.jar ./gatewayserver
docker build -t ostock/licensing-service:chapter12 --build-arg JAR_FILE=target/licensing-service-chapter12.jar ./licensing-service
docker build -t ostock/organization-service:chapter12 --build-arg JAR_FILE=target/organization-service-chapter12.jar ./organization-service

// 이미지 목록확인
docker images

다음은 도커 클라이언트를 ECR 레지스트리에 인증해야한다.
다음 명령을 실행하여 AWS 계정 ID와 패스워드를 얻어야 한다.

// 패스워드를 반환
aws ecr get-login-password

// AWS 계정을 반환
aws sts get-caller-identity --output text --query "Account"

// 이 두값을 사용하여 도커 클라이언트를 인증한다.
docker login -u AWS -p [password] https://[aws_account_id].dkr.ecr.ap-northeast-2.amazonaws.com
ex)
docker login -u AWS -p eyJwYXXXX... https://74023XXXXXXX.dkr.ecr.ap-northeast-2.amazonaws.com

인증을 완료했으면 이미지를 지정할 리포지터리를 만든다.
리포지터리를 생성하기 위해 다음 명령어 들을 실행하자.

aws ecr create-repository --repository-name ostock/configserver
aws ecr create-repository --repository-name ostock/gatewayserver
aws ecr create-repository --repository-name ostock/eurekaserver
aws ecr create-repository --repository-name ostock/authentication-service
aws ecr create-repository --repository-name ostock/licensing-service
aws ecr create-repository --repository-name ostock/organization-service

그리고 리포지터리 URI는 태그를 생성하고 이미지를 푸시하는 데 필요하므로 모든 리포지터리 URI를 기록하자

// 해당 명령어로 리포지터리 URI를 확인할 수 있다.
aws ecr describe-repositories

태그를 생성하기 위해 다음 명령어 들을 실행하자

// $1 부분에 자신의 account_id 를 입력하면 된다.
docker tag ostock/configserver:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/configserver:chapter12
docker tag ostock/gatewayserver:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/gatewayserver:chapter12
docker tag ostock/eurekaserver:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/eurekaserver:chapter12
docker tag ostock/authentication-service:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/authentication-service:chapter12
docker tag ostock/licensing-service:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/licensing-service:chapter12
docker tag ostock/organization-service:chapter12 $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/organization-service:chapter12

마지막 단계로 마이크로서비스 이미지를 ECR 레지스트리 리포지터리에 푸시하자
명령어는 다음과 같다.

// 마찬가지로 $1에는 자신의 account_id 이다.
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/configserver:chapter12
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/gatewayserver:chapter12
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/eurekaserver:chapter12
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/authentication-service:chapter12
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/licensing-service:chapter12
docker push $1.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/organization-service:chapter12

여기까지 완료되었으면
AWS 관리 콘솔의 ECR 서비스에서 PUSH된 목록을 확인할 수 있다

EKS 클러스터에 마이크로서비스 배포

마이크로서비스를 배포하기 전에 카프카 서비스와 주키퍼 서비스를 생성해 보자.
이 경우는 헬름 차트를 사용하여 서비스들을 생성했다.

헬름은 쿠버네티스 클러스터용 패키지 관리자다.
헬름 차트는 쿠버네티스 클러스터 내에서 특정 서비스, 애플리케이션 또는 도구를 실행하는 데 필요한 모든 리소스 정의가 포함된 헬름 패키지다.

먼저 헬름을 설치하자
(참고 https://helm.sh/docs/intro/install)

// Helm에는 최신 버전의 Helm을 자동으로 가져와 로컬에 설치 하는 설치 프로그램 스크립트가 있다.
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3

chmod 700 get_helm.sh

./get_helm.sh

헬름이 설치되었다면, 다음 명령을 실행하여 카프카와 주키퍼 서비스를 생성해 보자.

helm install zookeeper bitnami/zookeeper \
	--set replicaCount=1 \
	--set auth.enabled=false \
	--set allowAnonymousLogin=true
helm install kafka bitnami/kafka \
	--set replicaCount=1 \
	--set kafka.enabled=false \
	--set externalZookeeper.servers=zookeeper



// failed to download "bitnami/zookeeper" 가 나오면 아래 명령어를 사용해 Bitnami 리포지터리를 헬름에 추가한다.
helm repo add bitnami https://charts.bitnami.com/bitnami

모두 성공적으로 실행되었는지 확인하자

// 상태를 보는 명령어 (함께 배치된 컨테이너 그룹을 파드라고한다)
kubectl get pods

서비스의 배포의 다음단계는 도커 컴포즈 파일을 쿠버네티스와 호환 가능한 형식으로 변환하는 것이다.
쿠버네티스는 도커 컴포즈 파일을 지원하지 않기 때문에 실행하려면 Kompose 도구가 필요하다

Kompose는 도커 컴포즈 파일을 쿠버네티스 같은 컨테이너 구현체로 변환한다.
kompose convert 명령으로 모든 docker-compose.yml 파일 구성을 변환하고, kompose up 명령으로 docker-compose 파일을 실행하는 등 작업을 수행할 수 있다.

(여기서 쿠버네티스 파드를 등록하기 위한 매니페스트로 yaml 파일을 생성한다.)

다음 단계로 진행하기전에, 외부 IP주소에 서비스를 노출할 수 있는 쿠버네티스 서비스 종류먼저 살펴보자
다음 네 가지 타입의 서비스가 있다.

- ClusterIP : 클러스터 내부 ip에 서비스를 노출한다. 이 타입을 선택하면 서비스는 클러스터 내부에서만 볼 수 있다.
- 노드포트: 서비스를 고정 포트로 노출한다. 쿠버네티스는 3000 ~ 32767 사이의 기본 포트 범위를 할당한다. 
- 로드밸런서 : 클라우드 로드 밸런서로 서비스를 외부에 노출한다.
- 외부이름 : 외부 이름의 콘텐츠에 매핑한다.

프로젝트 폴더 하위 AWS/EKS 폴더를 보면 <service>.yaml 으로 된 파일들을 보면 type=NodePort와 nodePort 속성이 있는 것을 확인할 수 있다.
(spec.containers.commands 섹션에서 --sevice-node-port-range 플래그를 사용하여 포트를 변경할 수 있다.)
만약 쿠버네티스에서 서비스 타입을 정의하지 않았다면 기본 ClusterIP 타입을 사용한다.

이제 쿠버네티스 서비스 타입을 확인 했으므로 Kompose로 변환된 파일을 사용하여 서비스를 생성하기 위해 AWS/EKS 폴더에서 다음 명령을 실행한다.

// 쉼표사이에 스페이스가 없어야한다. 
ex) kubectl apply -f <service>.yaml,<deployment>.yaml

kubectl apply -f configserver-service.yaml,configserver-deployment.yaml
kubectl apply -f eurekaserver-service.yaml,eurekaserver-deployment.yaml
kubectl apply -f gatewayserver-service.yaml,gatewayserver-deployment.yaml
kubectl apply -f licensingservice-service.yaml,licensingservice-deployment.yaml
kubectl apply -f organizationservice-service.yaml,organizationservice-deployment.yaml
kubectl apply -f authenticationservice-service.yaml,authenticationservice-deployment.yaml

성공적으로 생성되었는지 확인하려면 개별적으로 이 명령을 실행할 것을 권하지만, 모든 서비스를 동시에 생성할 수도 있다. 이를 위해서는 이전 명령처럼 모든 yaml 파일을 -f 매개변수로 연결한다

예를 들어 구성 서버(configserver)를 생성하고 파드 상태와 로그를 보려면 다음 명령을 수행한다

// 구성서버 서비스 생성
kubectl apply -f configserver-service.yaml,configserver-deployment.yaml
// 파드 확인
kubectl get pods
// 파드 이름 기준으로 로그보기
kubectl logs <PDD_NAME> --follow

// pod, service, deployment를 삭제해야 한다면 아래의 명령 중 하나를 실행하면 된다
kubectl delete -f <service>.yaml
kubectl delete -f <deployment>.yaml
kubectl delete <PDD_NAME>

AWS/EKS 폴더 안에서 yaml 파일을 보면 postgres.yaml 파일이 약간 다른것을 알 수 있는데, 이 파일에서는 해당 데이터베이스 서비스를 외부 주소에서 사용하도록 지정한다.
데이터베이스와 연결되려면 RDS Postgres 서비스에 대한 엔드포인트를 지정해야 한다.

apiVersion: v1
kind: Service
metadata:
  labels:
    app: postgres-service
  name: postgres-service
spec:
  # Replace with your RDS URI, RDS PostgreSql 엔드포인트 설정(AWS RDS 데이터베이스 상세에 엔드포인트 주소가 나와있다)
  externalName: ostock-aws.c5l7dko00vxg.ap-northeast-2.rds.amazonaws.com
  selector:
    app: postgres-service
  type: ExternalName
status:
  loadBalancer: {}
// 이 변경을 적용하려면 해당 명령을 실행한다.
kubectl apply -f postgres.yaml

서비스가 실행 중인지 테스트하려면 노드포트에 들어오는 모든 트래픽을 허용하는 몇 가지 규칙을 보안 그룹에 추가해야한다.
이를 위해 다음 명령을 실행하여 보안 그룹 ID를 검색해보자

다음 명령어를 실행한다.

aws ec2 describe-security-groups --filters Name=group-name,Values="*eks-cluster-sg-ostock-dev-cluster*" --query "SecurityGroups[*].{Name:GroupName,ID:GroupId}"

보안 그룹 ID로 다음 명령을 실행해서 인바운드 규칙을 반들어 보자. AWS 관리 콘솔에서도 보안 그룹 메뉴로 이동해서 다음과 같은 새로운 인바운드 트래픽 규칙을 생성할 수 있다.

// security-group-id는 자신의 아이디로 각자 입력하면 된다.
aws ec2 authorize-security-group-ingress --protocol tcp --port 31000 --group-id [security-group-id] --cidr 0.0.0.0/0

이제 브라우저에서 URL을 호출해보가
그 전에 외부 IP를 얻으려면 아래 명령어를 실행하자

kubectl get nodes -o wide 

아래 사진의 EXTERNAL-IP 필드가 외부 ip 주소이다

(인스턴스를 한번 중지하고 다시 시작하여 Ip 주소가 변경되었다)

아래 URL로 접속해 본다. ( ex http:[node-external-ip]:[NodePort]/actuator )
http://3.35.174.91:31000/actuator

이로써 첫번째 작업인 아마존 EKS 클러스터에 성공적으로 배포 했다.


🧨 다음 챕터에서 두번째 작업으로,
구축한 ELK, EKS에서 서비스를 컴파일 및 패키징하고 아마존에 배포하는 프로세스를 자동화하는 빌드/배포 파이프라인 설계방법을 살펴보고 이를 기반으로 구축해보자

profile
노옵스를향해

0개의 댓글