티스토리 뷰

AWS EC2 인스턴스의 상태가 실행되거나 혹은 서버가 다운되었을 경우 이메일로 알람을 받아보는 기능을 구현하고자 한다.

 

공식문서를 보면 내용자체가 이해하기 어렵고 옛날자료들이 있다보니 정상적으로 돌아가지 않는부분도 있다. 그래서 이번에 삽질했던 내용으로 정리하고자 한다. 순서대로 정리하니 잘만 따라오면 문제없이 구현할 수 있다. ㅎㅎ

AWS EC2 인스턴스 생성

EC2 인스턴스 생성하는 방법은 여기를 보면 상세히 적어두었다. 여기에서 보안그룹 설정 및 키페어로 접근하는 과정도 나오는데 이번에는 그부분은 생략하고 단순히 생성만 해두자.

AWS SNS 주제 및 구독 생성

AWS Management Console에 들어가서 SNS이라고 검색후 접속하면 다음과 같은 화면이 나온다. '주제 생성' 버튼을 클릭하자.



유형을 '표준'으로 선택하자. 해당 주제를 구독한 사람에게 SNS가 전송되는데 메일로 전송을 할 것이기 떄문이다. 이름은 아무렇게나 지정해도 상관없다.

 

그리고 Amazon SNS는 CloudWatch에 Logging을 할 수 있는 권한이 있어야 하는데 기본값으로 생성하면 자동으로 권한이 부여된다. 기본값으로 생성하자.



주제가 생성되었으니 이제 구독을 생성하자. ARN값을 기억하도록 하자. 밑에서 JAVA 애플리케이션 개발할 때 다시 설명하겠다.



프로토콜을 '이메일'로 지정하고 엔드포인트에 SNS 전송받을 이메일을 입력하자.



구독도 정상적으로 생성되었다. 상태가 확인 대기중 이라고 되어있는데 확인완료 처리를 해야한다. 이제 등록한 엔드포인트 이메일로 로그인하여 메일함을 확인해보자.



메일함을 확인해보면 다음과 같은 메일이 왔는데 하단에 Confirm 버튼을 클릭하면 된다.



상태가 확인됨 이라고 처리되어 있으면 SNS 설정은 완료되었다.

AWS Lambda 함수 생성

이제 Lambda 함수를 생성하자. EC2 인스턴스의 상태가 변경되면 해당 Lambda 함수가 호출되도록 구성할 것 이다.



함수명을 작성하고 런타임은 JAVA 11로 설정해두고 함수를 생성하자.



JAVA 11로 개발된 애플리케이션을 jar로 빌드하여 업로드를 해주면 된다. 해당 코드에서는 AWS SDK를 이용하여 SNS로 메일을 전송하는 코드를 작성하면 된다. 이 부분은 밑에서 따로 설명하겠다.

 

여기서 눈여겨 봐야할 건 '런타임 설정'에 핸들러 라는 부분이다. example.Hello::handleRequest 라고 적혀있는데 :: 앞쪽에 나온건 패키지명.클래스명이고 :: 뒤쪽에 나온건 메서드명이다.

 

패키지명과 클래스명은 커스텀이 가능하지만 메서드명은 커스텀이 안된다. AWS Lambda SDK에 RequestHandler라는 인터페이스가 있는데 이 인터페이스의 메서드이고 얘를 구현해서 해당 메서드를 오버라이딩 해야한다. 이제 JAVA 애플리케이션을 생성하여 SNS 메일을 전송하는 코드를 작성하자.

JAVA 애플리케이션 생성

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-core</artifactId>
    <version>1.2.1</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-events</artifactId>
    <version>3.11.0</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-sns</artifactId>
    <version>1.12.131</version>
</dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20211205</version>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

pom.xml에 해당 라이브러리들과 플러그인 설정을 추가하자.

 

package example;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
import org.json.JSONObject;

public class Hello implements RequestHandler<Object, String> {
    private static final String ACCESS_KEY = "액세스키값";
    private static final String SECRET_KEY = "시크릿키값";
    private static final String REGION = "리전값";
    private static final String TOPIC_ARN = "주제 ARN값";
    private static final String RUNNING_MESSAGE = "테스트용 - 서버가 정상적으로 실행되었습니다.";
    private static final String STOPPED_MESSAGE = "테스트용 - 서버가 비정상적으로 종료되었습니다.";
    private BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
    private AWSStaticCredentialsProvider credentials = new AWSStaticCredentialsProvider(basicAWSCredentials);

    @Override
    public String handleRequest(Object event, Context context) {
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        LambdaLogger logger = context.getLogger();

        if (event != null && !event.toString().isEmpty()) {
            JSONObject jsonObject = new JSONObject(gson.toJson(event));
            logger.log("data ==> " + jsonObject);

            String state = jsonObject.getJSONObject("detail").getString("state");
            String time = jsonObject.getString("time");
            String message = String.format("EC2 인스턴스 상태 : %s, 현재시간(UTC) : %s", state, time);

            boolean isRunning = "running".equals(state);

            AmazonSNS build = AmazonSNSClient.builder().withCredentials(credentials).withRegion(REGION).build();

            PublishRequest publishRequest = new PublishRequest();
            publishRequest.setTopicArn(TOPIC_ARN);
            publishRequest.setSubject(isRunning ? RUNNING_MESSAGE : STOPPED_MESSAGE);
            publishRequest.setMessage(message);
            build.publish(publishRequest);
        }
        return null;
    }
}

Lambda 함수가 호출되면 handleRequest 메서드가 호출되는데 메서드 첫번째 인자에 EC2와 관련된 데이터들을 넣어준다. 어떤데이터가 들어가있는지는 밑에서 확인해보도록 하자. 두번째 인자엔 Context 타입의 인자를 넣어주는데 Cloud Watch의 Log관련된 메서드들과 Logger객체를 지원해준다.

 

'TOPIC_ARN' 변수에 들어갈 값은 아까 AWS SNS 주제를 생성하고 난 이후 발급된 ARN 값을 넣어주면 된다.

 

accessKey와 secretKey값은 AmazonSNSFullAccess Role을 소유한 IAM 사용자의 값을 넣어주면 된다. IAM 사용자에 Role을 부여하는 방법은 여기 를 참고하자.

 

이제 마지막으로 EC2 인스턴스의 상태가 변경될 때 Lambda 함수를 호출할 수 있도록 Event Bridge를 등록하자.

AWS Event Bridge 생성

이벤트가 발생할 규칙을 생성하자.



Event 이름과 설명을 작성하자.



패턴을 다음과 같이 정의하자. EC2의 상태가 'stopped', 'running' 상태일 때 동작하도록 구성하자.



대상과 함수를 설정해주자



Event가 정상적으로 생성되었다.



AWS Lambda쪽으로 다시 돌아오면 생성한 함수에 위에서 만든 Event 트리거가 추가된 걸 확인할 수 있다. '코드'탭을 누르고 위에서 작성한 JAVA 애플리케이션을 jar로 빌드해보자.

AWS EC2 인스턴스 중지

EC2 인스턴스를 중지시켜보자



그러면 Cloud Watch에 Lambda 함수이름의 로그가 생긴걸 확인할 수 있다.



data를 Logging해보니 EC2의 메타데이터 정보가 찍힌걸 볼 수 있다. detail의 state값이 현재 EC2 상태의 값이 'stopped' 된 걸 볼 수 있다.



SNS 메일이 정상적으로 전송되었다.

 

회사에서 서버에 장애가 발생되었던적이 있었는데 관리자외엔 접근할 수 없다보니 그대로 방치되었다. 이러한 기능을 도입함으로써 서버에 장애가 발생되어 EC2 인스턴스가 죽었을 때(stopped) 알람을 통해 빠르게 조치할 수 있게끔 구성하였다.

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함