[AWS] AWS SDK를 활용하여 인스턴스 관리 애플리케이션 만들어보기 (feat. AWS SDK JavaScript v3)

Woonil·2025년 3월 15일
0

AWS

목록 보기
1/1
post-thumbnail

Github 저장소

클라우드 컴퓨팅 교과목의 개인 프로젝트 과제를 수행하며 개인적으로 정리한 내용임을 미리 알립니다.

AWS에서 EC2 인스턴스를 생성하고 삭제하는 등 클라우드 환경에서 컴퓨팅 자원을 다루는 방법을 간단히 실습했었다. 그런데 만약 당신이 서버 관리자이고 EC2 인스턴스를 한 번에 100개를 생성해달라는 요청이 들어온다면 어떻게 할 것인가? 이를 AWS 콘솔을 통해 일일이 버튼을 클릭하고 있자하니, 관리자에게 그것 말고도 더 중요한 일이 많을 것이다. AWS에서는 AWS 서비스를 프로그래밍 방식으로 쉽게 사용할 수 있도록 AWS SDK(Services Software Development Kit)를 제공한다. 이를 활용하면 반복문으로 단 몇 초만에 인스턴스 대량 생성이 가능해 질 것이다. 뿐만 아니라, 프로그래머는 입맛에 맞게 aws 서비스를 자신이 잘 아는 프로그래밍 언어로 자신만의 애플리케이션을 만들어 볼 수도 있을 것이다.

이에 이전 과정에서 해보았던 HTCondor 클러스터를 AWS에 올리고, 동적으로 클러스터를 관리하는 간단한 프로그램을 만들어 보고자 한다. AWS는 Java, Python 등 몇 가지의 프로그래밍 언어의 SDK를 제공하며, 그 중 JavaScript SDK를 사용할 것이다. 아래는 프로그램 제작 시 활용한 AWS SDK for JavaScript(v3) 공식문서이며, 이 곳에 웬만한 서비스에 대한 api 활용법이 설명되어 있으니 참고하도록 한다.

AWS 공식문서 - AWS SDK for JavaScript v3

우선 웹 기반의 프로그램을 만들어야 하므로, JavaScript 런타임 환경인 Node.js로 서버를 로컬 환경에서 실행한다. Express.js 프레임워크를 사용하여 REST API를 구축할 것이며, 전체적인 애플리케이션 구조는 MVC 패턴을 따른다. (참고로 view에는 ejs를 활용한다.)

  • 프로젝트 폴더 구성
    ├───node_modules
    ├───public
    │   ├───css
    │   └───js
    ├───src
    │   ├───config # aws 관련 설정 파일
    │   ├───controller # 컨트롤러
    │   ├───routes # 라우터
    │   ├───service # 서비스
    │   │   └───ec2
    │   └───utils # 기타 함수
    └───views
        └───ec2 # 뷰
  • API 구축
    Postman에 api를 정리하고, 테스트에 활용했다.

  • 환경 변수
    AWS SDK를 사용하려면 AWS 리전정보, 액세스 키 정보가 필수적이다. 이를 위해.env 를 채워넣도록 한다.

        # .env.example
        AWS_REGION= # AWS 리전
        AWS_ACCESS_KEY_ID= # AWS 액세스 키
        AWS_SECRET_ACCESS_KEY= # AWS 비밀 액세스 키
        # 부가 정보
        PORT= # 서버 실행 포트
        HTCONDOR_TAG_KEY=Name # HTCondor 클러스터 태그 키
        HTCONDOR_TAG_PREFIX=HTCondor_Data # HTCondor 클러스터 태그명 접두사
        HTCondor_SG_ID=sg-xxxx # HTCondor 클러스터가 속한 보안그룹

🧐수행 과정

전체적인 아키텍쳐는 그림을 참고한다. 참고로 데이터 노드는 N개(최대 10개) 생성 가능하다.

HTCondor 관련 사전 작업 수행하기

  1. 보안 그룹 생성
    HTCondor 클러스터 내 노드 간에 통신을 수행할 수 있도록 보안그룹을 생성한다. 이때, 보안 그룹 이름을 지정하고, 인바운드 규칙에 대해서는 TCP 프로토콜의 9618번 포트와 SSH 접속을 위해 22번 포트를 열어둔다. 아웃바운드 규칙에 대해서는 IPv4의 모든 트래픽을 허용한다. 이후 생성할 HTCondor 노드들에 대해 이번 과정에서 생성한 보안 그룹을 적용한다.
  2. 컨트롤 노드 생성
    HTCondor 클러스터 구성을 위해 AWS 콘솔에 접속한 후, 컨트롤 노드가 되는 인스턴스를 생성한다. 해당 인스턴스가 컨트롤 노드로서 수행할 수 있게 사전 작업을 수행한다. (자세한 설정 과정은 생략한다.)

  3. 데이터 노드 생성
    데이터 노드로서 수행할 인스턴스도 생성한 후, 관련 작업을 수행한다.
  4. condor 명령어 수행
    클러스터에 속한 컨트롤 노드에 접속해 condor_status 명령의 결과가 제대로 나오는지 확인한다. 데이터 노드가 클러스터에 잡힌 것을 확인할 수 있다.

  5. 데이터 노드의 AMI 생성
    이후 클러스터의 데이터 노드를 늘리기 위해서는 관련 설정이 포함된 AMI가 있으면 빠르게 인스턴스를 생성할 수 있을 것이다. 따라서 데이터 노드로부터 AMI를 생성한다.

AWS 클라이언트 객체 생성

인스턴스를 생성하고, 조회하는 등의 작업을 수행하려면 중간자 역할을 수행하는 클라이언트가 필요하다. 따라서 관련 클라이언트 객체를 생성하는 코드를 작성한다. 이후 동일한 객체가 인스턴스와 관련한 일련의 작업을 수행할 것이다.

  • aws-config.js
        // 예시
        // CONFIG: EC2 클라이언트 객체
        export const ec2ClientConfig = {
          region: process.env.AWS_REGION,
          credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY_ID,
            secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
          },
        };
  • aws-client.js
        // 예시
        export const ec2Client = new EC2Client(ec2ClientConfig);

구현

서비스

실제 작업을 수행하는 서비스 단의 코드를 작성하도록 한다. 아래는 현재 생성된 인스턴스 목록을 조회하는 함수이다.

/**
 * SERVICE: 인스턴스 목록을 조회하는 함수
 * @returns {Array} instances - 배열 형태의 인스턴스 정보
 */
import { DescribeInstancesCommand } from "@aws-sdk/client-ec2";
import { ec2Client } from "../aws-client.js";

const listInstances = async () => {
  const command = new DescribeInstancesCommand({});
  try {
    const { Reservations } = await ec2Client.send(command);

    // 인스턴스 정보를 담을 배열
    const instances = [];

    Reservations.forEach((reservation) => {
      reservation.Instances.forEach((instance) => {
        // 필요한 정보만 추출하여 객체 생성
        const instanceInfo = {
          Name:
            instance.Tags?.find((tag) => tag.Key === "Name")?.Value ||
            "No Name",
          InstanceId: instance.InstanceId || "N/A",
          ...
        };

        // 인스턴스 정보를 배열에 추가
        instances.push(instanceInfo);
      });
    });

    // 추출한 인스턴스 정보 반환
    return instances;
  } catch (caught) {
  }
};

export default listInstances;

컨트롤러

컨트롤러를 작성한 후, 라우터에 등록한다. 응답값을 바탕으로 인스턴스 목록을 HTML로 보여주는 instances.ejs 도 작성한다.(생략)

// GET /instances
export const listInstances = async (req, res) => {
  try {
    const existingInstances = await ec2Service.listInstances();

    return res.render("ec2/instances", { instances: existingInstances });
  } catch (error) {
    return res.status(500).json({
      status: "error",
      message: error.message || "Failed to list instances",
    });
  }
};
import { Router } from "express";
import { listInstances } from "../controller/ec2.controller.js";

const router = Router();
// GET instances
router.get("/instances", listInstances);

export default router;

이와 같이 다른 서비스들에 대해서도 서비스, 컨트롤러, 뷰를 구성한다. 서비스 구성 함수는 다음과 같다.

└───service
    └───ec2
        ├───list-instances.service.js # list instance
        ├───list-availability-zones.service.js # availability zones 
        ├───list-availability-regions.service.js # available regions
        ├───control-instances.service.js # start/stop/reboot instance
        ├───create-instances.service.js # create instance
        ├───list-images.service.js # list images
        ├───get-condor-status.service.js # get result of condor_status command 
        ├───get-condor-queue-status.service.js # get result of condor_q command 
        ├───get-htcondor-metrics.service.js # get CloudWatch result of cluster
        ├───create-asg.service.js # create autoscaling group
        └───submit-condor-job.service.js # submit condor job to cluster

인스턴스, AMI 관련

인스턴스를 생성/시작/중지/재시작할 수 있게 화면을 구성하였다.

  • 인스턴스 관리 페이지

클러스터 조회하기

클러스터의 컨트롤 노드의 공인 IP를 입력하여 클러스터 상태를 조회할 수 있게 했다. 웹 워커를 사용하여 condor_status , condor_q, condor_submit 명령어를 수행하고 결과를 반환하게 구현하였고, 대시보드를 통해 결과를 확인할 수 있게 하였다.

  • 컨트롤 노드 공인 IP 입력
  • 대시보드 확인
  • startcondor_status 확인
  • stopcondor_status 확인 (생략)
  • createcondor_status 확인

AWS 서비스 붙여보기

Auto Scaling

AWS SDK for JavaScript v3 - Auto Scaling

  • ASG(Auto Scaling Group) 생성
    시작 템플릿(보안그룹: HTCondor 클러스터가 존재하는 보안그룹/리소스 태그: 키는 Name, 값은 HTCondor_Data로 설정)은 이미 생성이 되어있다는 전제 하에 ASG를 생성할 수 있게 구현하였다.

    AWS SDK for JavaScript v3 - 오토스케일링그룹 생성

  • Automatic Scaling Policy API 생성

    오토스케일링 그룹의 동적 크기 조정 정책을 생성할 수 있게 구현하였다. (이는 이후 CloudWatch의 경보 기능과 연동할 때 사용된다.)
    AWS SDK for JavaScript v3 - 동적 크기 조정 정책 수정

    동적 크기 조정 정책

    수요 변화에 맞춰 오토 스케일링의 규모를 조정하며, 반응형 동적 크기 조정 정책을 사용하면 특정 CloudWatch 지표를 추적하고 CloudWatch 경보 임계값에 도달할 때 조치를 취할 수 있다.

Cloud Watch

AWS SDK for JavaScript v3 - CloudWatch

  • 경보 생성
    AWS SDK for JavaScript v3 - 경보 생성
    이전 과정에서 생성한 스케일링 정책 ARN, 경보 이름, 임계값(ex. 80), SNS 주제(AWS 콘솔을 통해 미리 생성해 놓은 것을 전제로 함)를 선택할 수 있게 모달창을 구성하였다.
  • HTCondor 작업 제출/큐 상태 확인
    컨트롤 노드의 IP를 입력한 후, 파일(예시에선, CPU에 부하를 줄 만한 작업이 작성된 쉘 스크립트)을 업로드한 후, 제출 버튼을 클릭하면 작업 큐에 새로운 작업이 들어간 것을 확인할 수 있게 구현하였다.

    #!/bin/bash
    
    # CPU 부하를 위해 4개의 무한 루프 생성
    for i in {1..4}; do
        while :; do :; done &
    done
    
    # 300초 동안 유지 후 종료
    sleep 300
    killall -9 bash
  • CPU 메트릭 확인
    데이터 노드들의 CPU 사용량을 조회하여 그래프를 통해 구현하였다. (Chart.js 활용)
    AWS SDK for JavaScript v3 - 메트릭 조회

    AWS 콘솔에서 확인

  • 메일 수신 확인
    생성해 두었던 SNS에 설정한 이메일로 알람이 수신된 것을 확인할 수 있다.

  • 새로운 노드 생성 확인
    CPU 사용률이 임계점을 넘김으로써 기존에 1개였던 데이터 노드가 2개로 늘어난 것을 확인(동적 크기 조정 정책을 1로 설정했음)할 수 있다. (사진 생략)

🤔트러블 슈팅

Your requested instance type (<instance type>) is not supported in your requested Availability Zone (<instance Availability Zone>)...

오토스케일링 그룹 생성 시, ‘유효하지 않은 가용 영역’이라는 오류가 나며 생성을 실패한 경우가 발생했다. 이는 인스턴스 유형에 따라 가용 영역이 제한되는 경우가 있었기 때문이고, 인스턴스에 맞는 가용영역을 선택하여 해결하였다.

Amazon EC2 Auto Scaling 문제 해결: EC2 인스턴스 시작 실패 - Amazon EC2 Auto Scaling

profile
프론트 개발과 클라우드 환경에 관심이 많습니다:)

0개의 댓글

관련 채용 정보