새소식

반응형
AWS/운영관련 개발

AWS monitoring - Cloud Watch 기반 CPU 10%미만 EC2 정보 수집

  • -
반응형

글을 읽기에 앞서 해당 코드는 python 및 개발 지식이 없는 제가 직접 만든 코드 입니다. 개발자 분이 보시기에 많이 이상 할 수 있습니다. 최적화가 되어 있지 않으며, 코드를 보기에 불편 할 수 있는 점 양해 부탁 드립니다.

 

 

1. 수집 조건

  • Cloud Watch 상에서 하루 평균 CPU가 10%를 넘지 못하는 경우 수집 
    • limit를 조정 가능 합니다. 
    • 코드를 수정하면 MAX / MIN으로도 수정 가능 합니다.
  • spot EC2를 수집 하지 않습니다. 

 

2. 수집 내역

아래의 컬럼명은 수정이 가능하며, 기호에 맞게 사용 부탁 드립니다. 

계속해서 수정하다 보니 수집하는 명칭이 이상할 수 있습니다.

  • account : AWS 계정명
  • isinstance_id : EC2의 Instance ID
  • InstanceType : EC2의 Instance 타입
  • InstanceName : EC2명 / tag 기반으로 가져 옵니다. (코드에 설명 있음)
  • InstanceCreate : EC2생성자 or 팀 / tag 기반으로 가져 옵니다. (코드에 설명 있음)
  • region : EC2가 속해있는 리전
  • metric_type : Cloud watch에 명 / CPUUtilization가 기본 값
  • cpu_max : 일일 최대 CPU 값
  • cpu_min : 일일 최소 CPU 값
  • cpu_persent : 일일 평균 CPU 값
  • timestamp : 수집 시간
  • SubnetId : EC2가 속해 있는 subnet
    • Subnet의 경우 EC2가 많기 때문에 Subnet을 팀별로 생성하여 EC2를 관리하였기에 subnet을 수집하여 차후에 비용 계산시 Subnet 별로 계산하면 팀별 비용 산정이 가능하여 수집합니다. (아래의 keypair도 같은 이유에서 수집)
  • Keypair : EC2에 속해 있는 keypair

 

3. 코드

변경하여 사용 가능한 부분 또는 설명이 필요한 부분만 설명 합니다.

나머지는 주석으로 되어 있습니다.

- import library 

아래의 pymssql이 있는데, 사용자에 맞게 mysql , postgreSQL 등등 불러서 사용하시면 사용 가능 합니다.

1
2
3
4
import boto3
import sys
import pymssql
import datetime
cs

 

- AWS 연결 정보 부분 

아래의 key_list 부분에서 여러개의 Account를 관리 할 수 있도록 해당 Account 및 access,secret key만 넣으면 전부 수집하도록 해놨습니다. 각각의 정보 구분자는 | 이며 서로 다른 Account를 구분하는 것은 , 콤마 입니다.

1
2
3
4
5
6
7
8
9
10
#AWS information 
#"," multiple entries available 
#key_list = ['ACCOUNT|ACCESS KEY|SECRET KEY','ACCOUNT2|ACCESS KEY2|SECRET KEY2','ACCOUNT2|ACCESS KEY2|SECRET KEY2']
key_list = ['ACCOUNT|ACCESS KEY|SECRET KEY']
#Enter desired region information
region_list = ['us-east-2','us-west-1','us-west-2','ap-south-1','ap-northeast-2','ap-southeast-1','ap-southeast-2','ap-northeast-1','eu-central-1','eu-west-1','eu-west-2','eu-west-3','sa-east-1']
access_key = ''
secret_key = ''
region =  ''
boto3.session.Session(aws_access_key_id=access_key, aws_secret_access_key=secret_key)
cs

region_list의 경우 원하는 region만 넣으면 가능합니다.

 

- tag 수집 부분

tag를 이용해서 EC2의 이름 및 생성자를 가져옵니다. 

꼭 Name , name 으로 입력해야지 가져올 수 있습니다. 생성자 또한 create / creator을 통해서 가져 옵니다.

여담으로 AWS쪽에 관리를 위해서는 tag는 필수라고 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#Import EC2 tag 
#EC2 tag name > tag name : Name
#EC2 tag creator or create team > tag name : create or creator
def get_instance_tag(fid):
    global result, result2
    result = ''
    result2 = ''
    ec2client = boto3.resource('ec2',aws_access_key_id=access_key, aws_secret_access_key=secret_key,region_name=region)
    ec2instance = ec2client.Instance(fid)
    if ec2instance.tags is None: #tag가 아에 없을 경우 PASS
        return (result,result2)
    for tags in ec2instance.tags:
        if tags.get("Key"is None: continue    #tags key 체크
        if tags.get("Key").lower() == 'Name'.lower():
            result = tags.get("Value")
        if tags.get("Key").lower() == 'create'.lower() or tags.get("Key").lower() == 'creator'.lower():
            result2 = tags.get("Value")
    return (result,result2)
cs

 

- 전체 코드

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import boto3
import sys
import pymssql
import datetime
# -----------------------------------------------------------------------------------------------------------------------------------------------
#AWS information 
#"," multiple entries available 
#key_list = ['ACCOUNT|ACCESS KEY|SECRET KEY','ACCOUNT2|ACCESS KEY2|SECRET KEY2','ACCOUNT2|ACCESS KEY2|SECRET KEY2']
key_list = ['ACCOUNT|ACCESS KEY|SECRET KEY']
#Enter desired region information
region_list = ['us-east-2','us-west-1','us-west-2','ap-south-1','ap-northeast-2','ap-southeast-1','ap-southeast-2','ap-northeast-1','eu-central-1','eu-west-1','eu-west-2','eu-west-3','sa-east-1']
access_key = ''
secret_key = ''
region =  ''
boto3.session.Session(aws_access_key_id=access_key, aws_secret_access_key=secret_key)
# -----------------------------------------------------------------------------------------------------------------------------------------------
#Import date
now = datetime.datetime.now()
today = str(now)
today = today.split(' ')[0]
yesterday = str(now + datetime.timedelta(days=-1))
yesterday = yesterday.split(' ')[0]
# -----------------------------------------------------------------------------------------------------------------------------------------------
#Database information
conn = pymssql.connect(server='HOST',port= 'PORT', user='USER', password='PASS WORD',database='DATABASE NAME')
cur = conn.cursor()
# -----------------------------------------------------------------------------------------------------------------------------------------------
#CPU mean value calculation 
def CPUUtilization_check(isinstance_id):
    cloudwatch = boto3.client('cloudwatch', aws_access_key_id=access_key, aws_secret_access_key=secret_key,region_name=region)
    cpu_limit = 10 #Modifying here allows you to change the collection conditions.
    response = cloudwatch.get_metric_statistics(
            Namespace='AWS/EC2',
            MetricName='CPUUtilization',
            Dimensions=[
                {
                'Name''InstanceId',
                'Value': isinstance_id
                },
            ],
            StartTime=yesterday ,
            EndTime=today,
            Period=86400,    #시간 단위 (1시간 = 3600)
            Statistics=['Minimum','Maximum','Average'], #Cloudwatch의 그래프는 Average
            Unit='Percent'
            )
    for cpu in response['Datapoints']:
        if 'Average' in cpu:
            result = 'CPUUtilization'+'/'+str(cpu['Average'])+'/'+str(cpu['Timestamp'])[0:16]+'/'+str(cpu['Minimum'])+'/'+str(cpu['Maximum'])
            metric_type = result.split('/')[0]
            cpu_persent = result.split('/')[1]
            timestamp = result.split('/')[2]
            cpu_max = result.split('/')[3]
            cpu_min = result.split('/')[4]
            if float(cpu_persent) <= cpu_limit:
                param = (account,isinstance_id,InstanceType,InstanceName,InstanceCreate,region,metric_type,cpu_max,cpu_min,cpu_persent,timestamp,SubnetId,Keypair)
                cur.callproc('dbo.usp_insert_permon', param) # mssql procprocedure
                conn.commit()
# -----------------------------------------------------------------------------------------------------------------------------------------------
#Import EC2 tag 
#EC2 tag name > tag name : Name
#EC2 tag creator or create team > tag name : create or creator
def get_instance_tag(fid):
    global result, result2
    result = ''
    result2 = ''
    ec2client = boto3.resource('ec2',aws_access_key_id=access_key, aws_secret_access_key=secret_key,region_name=region)
    ec2instance = ec2client.Instance(fid)
    if ec2instance.tags is None: #tag가 아에 없을 경우 PASS
        return (result,result2)
    for tags in ec2instance.tags:
        if tags.get("Key"is None: continue    #tags key 체크
        if tags.get("Key").lower() == 'Name'.lower():
            result = tags.get("Value")
        if tags.get("Key").lower() == 'create'.lower() or tags.get("Key").lower() == 'creator'.lower():
            result2 = tags.get("Value")
    return (result,result2)
# -----------------------------------------------------------------------------------------------------------------------------------------------
for key in key_list:
    account = key.split('|')[0]
    access_key = key.split('|')[1]
    secret_key = key.split('|')[2]
    print((account, access_key, secret_key))
    # -----------------------------------------------------------------------------------------------------------------------------------------------
    for region_name in region_list :
        region = region_name
        ec2client  = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key,region_name=region)
        response = ec2client.describe_instances(Filters=[{'Name''instance-state-name''Values': ['stopped''running']}])
        if response is None:
            continue
        for reservation in response.get("Reservations"):
            if reservation is None:
                continue
            for instance in reservation["Instances"]:
                SpotInstanceRequestId = (instance.get("SpotInstanceRequestId")) #Spot instance check
                if SpotInstanceRequestId is None:
                    isinstance_id = (instance.get("InstanceId"))
                    InstanceType = (instance.get("InstanceType"))
                    InstanceName = (get_instance_tag(isinstance_id)[0])
                    InstanceCreate = (get_instance_tag(isinstance_id)[1])
                    SubnetId =  (instance.get("SubnetId"))
                    Keypair = (instance.get("KeyName"))
                    if None in [SubnetId,InstanceName,isinstance_id,InstanceType,InstanceCreate,Keypair,InstanceName,InstanceCreate]:
                       continue
                    #print((isinstance_id,SpotInstanceRequestId,InstanceType,InstanceName,InstanceCreate,SubnetId,Keypair))
                    CPUUtilization_check (isinstance_id)
        print ('insert ok',account,'-',region)
# -----------------------------------------------------------------------------------------------------------------------------------------------
 
 
cs

 

위에서 수집 된 내용을 토대로 비용 관리 및 불 필요하게 가동 중인 EC2 등을 중지 시킬 수 있습니다.

비용 정보는 https://ec2instances.info/ 사이트를 통해서 가져 올 수 있습니다. (AWS 공식 제공)

 

Amazon EC2 Instance Comparison

 

ec2instances.info

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.