특정 태그가 있는 Instance 자동 시작/정지 bot 너를 AWS Lambda로 만들기

마법의 말, 경비 절감


  • 개발 환경에 EC2를 사용하면 귀가시 Instance의 Shtdown을 잊어 버리는 경향이 있습니다.
  • 「먼지도 쌓이면 산이 된다」라는 말이 있다고 합니다.
  • 어쩌면 아무데도 비슷한 일을하고있는 EC2 Instance의 자동 정지 bot 너를 Lambda로 만든다.
    (잔업 많은 회사라면 존재를 누구나가 잊었을 무렵에 비극의 Shutdown을 가차없이 풀어 비교적 존재 미움받기 쉽다)
  • Lambda에 ScheduleEvent가 붙어 매일 cron 실행할 뿐인 Instance를 죽일 기회.

  • 선인님의 참고 등


  • Role이라든가 GUI의 설정 주위는 이 근처에서 잡아 주면.
    [클래스 메소드]
    Lambda Schedule 이벤트에서 EC2를 자동 시작 및 자동 중지해 보았습니다.
    EC2와 RDS, ELB 정지 잊어버리고 삭제 잊지 않도록! LambdaSchedule 이벤트

  • 이번에 하고 싶은 일


  • 지금까지는 시업 시간에 자동 기동, 밤 조금 늦은 시간에 자동 정지하는 cron 실행 전용 EC2가 있었다.
  • 자동 기동할 때는, 제대로 토, 일, 공휴일을 판별하고, 평일만 자동 기동시킨다.
  • Lambda의 python이라고 표준으로 boto3를 사용할 수 있으므로, Filter라든지로 특정 태그의 Instance에 대상을 짜낸다.

  • 평일 or 주말 or 공휴일


  • 평일 or 토일의 판정에는, Lambda의 ScheduleEvent(cron)로 MON-FRI를 지정하면 평일만 실행할 수 있는 것이, 후술의 UTC 문제가 있기 때문에 필요한 경우는 python 표준의 date.weekday( ) 등 사용
  • 공휴일의 판정에는 여러가지 있지만 결국 Google 캘린더님의 일본의 공휴일에 의지한다.
    그래서, Google 근제의 python 모듈이 있으므로 사용하게 한다.
    google-api-python-client

  • Lambda에서 외부 모듈을 사용할 때는 zip으로 코드 전체 업로드


  • Lambda에는 코드를 작성하는 방법이 두 가지 있으며 브라우저에서 인라인 편집하면서 작성하는 방법과 외부 모듈을 사용하고 싶으면 모듈별 zip으로 코드를 업로드하는 방법이 있다.
  • google-api-python-client는 당연히 사용할 수 없으므로 pip로 임의 디렉토리에 로컬 설치한다.
  • cd [適当なディレクトリ]
    sudo pip install --upgrade google-api-python-client -t ./
    
    # 同じディレクトリ内でLambdaで実行するメインファイルを書く
    vim hoge.py
    

    hoge.py
    import boto3
    import datetime
    import sys
    
    from apiclient.discovery import build
    
    
    # https://console.developers.google.com/project ここらへんから
    API_KEY = '[Googleの開発APIキー]'
    CALENDAR_ID = 'ja.japanese#[email protected]'
    
    # 年末年始とか会社の休みは自動起動しない(YYYY-MM-DDで列挙)。
    company_holiday_list = []
    
    
    # 関数名(ここではlambda_handler)と、ファイル名(ここではhoge.py)を
    # LambdaのHandler名に設定する ex.) hoge.lambda_handler
    def lambda_handler(event, context):
        client = boto3.client('ec2')
    
        # タグ名「AutoShutdown」がAUTOだと自動起動/停止
        # タグ名「AutoShutdown」がONだと自動停止のみ行う
        query_start = [
            {'Name': 'tag:AutoShutdown', "Values": ['AUTO']},
            {'Name': 'instance-state-name', "Values": ['stopped']}
        ]
        query_stop = [
            {'Name': 'tag:AutoShutdown', "Values": ['ON', 'AUTO']},
            {'Name': 'instance-state-name', "Values": ['running']}
        ]
    
        service = build(serviceName='calendar', version='v3', developerKey=API_KEY)
        events = service.events().list(calendarId=CALENDAR_ID).execute()
        holiday_list = []
    
        for item in events['items']:
            holiday_list.append(item['start']['date'])
    
        holiday_list.extend(company_holiday_list)
    
        # 発火元event名の確認
        try:
            # 自動起動の場合は土日祝日を除く平日のみ動作させる
            if '[Event sourceのARN(自動起動用ScheduleEvent)をコピー]' in event['resources']:
                if not str(datetime.date.today()) in holiday_list:
                    client.start_instances(InstanceIds=get_instanceid(query_start))
    
            elif '[Event sourceのARN(自動停止用ScheduleEvent)をコピー]' in event['resources']:
                client.stop_instances(InstanceIds=get_instanceid(query_stop))
    
            elif '[Event sourceのARN(自動停止X分前告知用ScheduleEvent)をコピー]' in event['resources'] \
                    and (not str(datetime.date.today()) in holiday_list):
                # 5分とか10分前にSlack通知するような処理をここに書くとより親切(自動停止爆死予防)
    
        except Exception as e:
            # エラー処理。Slackにスタックトレース投げるとか。
    
        print("SUCCESS: task succeeded")
        return
    
    
    def get_instanceid(query):
        client = boto3.client('ec2')
        response = client.describe_instances(Filters=query)
    
        ec2_count = len(response['Reservations'])
        ec2_list = []
    
        if not ec2_count == 0:
            for i in range(0, ec2_count):
                ec2_list.append(response['Reservations'][i]['Instances'][0]['InstanceId'])
            return ec2_list
        else:
            print("SUCCESS: specified hosts is None")
            sys.exit()
    
  • Lambda에 코드 업로드
  • zip -r ~/hoge.zip .
    aws lambda update-function-code --function-name [Lambda作成時に設定したfunction名] --zip-file fileb://~/hoge.zip
    

    일단 보충


  • [Event source ARN]을 각 환경으로 다시 작성하십시오. m (__) m
    이하의 화상으로 말하는 ARN의 부분을 말과 코피페입니다.

  • 자동 기동/정지로 일일이 Lambda의 Function을 복수로 나누고 싶지 않기 때문에,
    발화원 event(ScheduleEvent명)에 의해 start인지 stop인지를 분기시킨다.
  • Lambda의 ScheduleEvent는 어디까지나 UTC이므로 설정과 취급에는 주의!
    예를 들면 JST에서 아침 8시에 자동 기동시키고 싶다! 그렇다면, UTC라면 JST와 날짜가 바뀌기 때문에 자동 기동하지 않는다든가.

  • ※이 엔트리는 python 초보자가 작성한 것으로, 완전한 동작을 보증하는 것은 아닙니다. 오히려 좋은 가감한 아레입니다.

    좋은 웹페이지 즐겨찾기