Tự động Start & Stop AWS EC2 instances sử dụng Tags

Tự động Start & Stop AWS EC2 instances sử dụng Tags

March 19, 2019 Off By harvey

Ai từng sử dụng các dịch vụ của AWS thì đều có thể đã biết, mặc dù AWS tính phí chủ yếu dựa theo hình thức “Pay-as-you-go”, nhưng nếu bạn quên tắt 1 dịch vụ gì đó như EC2, ELB hay RDS,… thì chi phí phát sinh ra có thể sẽ gây tổn thất không nhỏ cho công ty, doanh nghiệp hay chính cá nhân bạn. Bài viết này tập trung chủ yếu vào nhu cầu tự động Start hay Stop các EC2 instances dựa theo Tags. Việc tự động hóa này có thể tiết kiệm cho bạn rất nhiều tiền và thời gian, hơn thế bạn có thể chú tâm hơn vào các công việc khác. Ở đây, mình đề cập đến 2 phương pháp cho việc tự động Start & Stop EC2 instances này nhé :))

Phương pháp 2 sẽ tốt hơn phương pháp 1, tuy nhiên để cho các bạn có cái nhìn tổng quan nhất về công việc tự động hóa này thì mình sẽ đề cập đến cách 1 trước nhé.

1. Sử dụng Lambda + CloudWatch

Ý tưởng của chúng ta như sau: Trước tiên, chúng ta cần tạo 1 IAM Role cho Lambda function của chúng ta. IAM Role này sẽ cho Lambda function các quyền (permission) để thực thi việc Start, Stop và lấy thông tin các EC2 instances của chúng ta. Từ đó, Lambda có thể dựa vào tags để xác định các EC2 server mà chúng ta cần.

Tiếp theo, đương nhiên rồi, chúng ta sẽ định nghĩa ra 1 hàm Lambda cho việc Start & Stop này (mình sẽ cung cấp mã nguồn ở dưới bài viết cho các bạn nhé). Hàm Lambda này sẽ chạy khi có 1 CloudWatch Event gọi đến nó. Và CloudWatch Event này sẽ được định nghĩa tùy theo nhu cầu của các bạn.

Ở đây, CloudWatch Event của mình sẽ trigger Lambda function để nó tự động khởi động 1 con EC2 vào lúc 8 giờ sáng và cũng vậy, tự động dừng nó lại vào lúc 7h tối.

Vậy, chúng ta cùng bắt đầu nào!

1.    Trước hết, chúng ta hãy vào Lambda console (Có thể truy cập vào từ Services -> Compute), sau đó chọnCreate function.

2.    Tiếp tục chọn Author from scratch để xây dựng 1 Lambda function trống.

3.    Tiếp đến, ta thiết lập các thông số cho Lambda function như sau nhé:
Với Name, ta nhập vào tên cho hàm Lambda của chúng ta, ví dụ như là: “StopEC2Instances”.
Với Runtime, chọn Python2.7. (Nếu bạn biết Python, bạn cũng có thể chọn Python3 hoặc 1 ngôn ngữ khác phù hợp với bạn, ở đây mình dùng code của Python2 nên mình chọn Python2.7 nhé)
Với Role, chọn Create a custom role. Một trang mới sẽ mở ra và chúng ta có thể thấy đang trong giao diện của IAM console.

4.    Trong trang này, dưới mục Role Summary, thiết lập các thông số như sau:
Với IAM Role, chọn Create a new IAM Role.
Với Role Name, chọn 1 tên cho role của chúng ta (hãy chọn 1 tên nào có nghĩa 1 chút nhé :)), “lambda_stop_start_ec2.”

5.    Chọn View Policy Document, và sau đó chọn Edit.

6.    Trong phần Edit Policy, đọc phần documentation nếu cần thiết, và sau đó chọn tiếp Ok.

7.    Copy đoạn mã policy sau (được viết theo ngôn ngữ JSON) và paste nó vào trong phần chỉnh sửa policy (policy editor), lưu ý là xóa cả phần policy đã có sẵn rồi đi nhé:

{
“Version”: “2012-10-17”,
“Statement”: [
{
“Effect”: “Allow”,
“Action”: [
“logs:CreateLogGroup”,
“logs:CreateLogStream”,
“logs:PutLogEvents”
],
“Resource”: “arn:aws:logs:*:*:*”
},
{
“Effect”: “Allow”,
“Action”: [

“ec2:DescribeInstances”,
“ec2:Start”,
“ec2:Stop”
],

“Resource”: “”
}
]
}

8.    Chọn Allow để hoàn tất việc tạo custom role và trở lại với giao diện Lambda console.

9.    Trong giao diện của Lambda console, chọnCreate function.

10.    Copy đoạn code sau, rồi ở mục Function code, paste toàn bộ vào phần editor pane in the code editor (lambda_function). Đoạn code này sẽ stop EC2 instances mà bạn chỉ định dựa theo Tags. (Tags của mình ở đây là KeyAutoOff và Valuetrue nhé, bạn có thể sửa lại tùy theo nhu cầu)

import boto3
import logging

#setup simple logging for INFO
logger = logging.getLogger()
logger.setLevel(logging.INFO)

#define the connection
ec2 = boto3.resource(‘ec2’)

def lambda_handler(event, context):
# Use the filter() method of the instances collection to retrieve
# all running EC2 instances.
filters = [{
‘Name’: ‘tag:AutoOff’,
‘Values’: [‘True’]
},
{
‘Name’: ‘instance-state-name’,
‘Values’: [‘running’]
}
]
#filter the instances
instances = ec2.instances.filter(Filters=filters)

#locate all running instances
RunningInstances = [instance.id for instance in instances]

#print the instances for logging purposes

#print RunningInstances

#make sure there are actually instances to shut down.
if len(RunningInstances) > 0:

#perform the shutdown
shuttingDown = ec2.instances.filter(InstanceIds=RunningInstances).stop()

Trong đoạn code trên, nếu như tag mà bạn gắn cho server của mình không phải là AutoOff với giá trị là true thì bạn phải sửa lại 2 thông số này nhé.
Ở đây, ‘Name’: ‘tag:AutoOff’ là Key của tag và ‘Values’: [‘True’] là Value của tag. Hãy sửa lại cho phù hợp với các server của bạn.

11.    Ở mục Basic settings, điền thông số cho Timeout là 10 sec. Còn phần Description thì bạn hãy tự viết mô tả cho hàm này của mình. Lưu ý là hãy viết 1 cách thật tường minh nhé.

12.    Đến đây là xong phần thiết lập hàm Lambda rồi, giờ hãy ấn nút Save ở phía trên bên phải của màn hình giao diện nhé.

13.    Lặp lại từ bước 1-12 để tạo thêm 1 function nữa. Tuy nhiên, ở 1 vài bước sau sẽ hơi khác 1 chút để có thể có hàm auto Start các EC2 instances
Ở bước 3, nhập tên Name là 1 tên gì đó nói lên mục đích của hàm. Ở đây sẽ là “StartEC2Instances”
Ở bước 3, với Role, vẫn chọn role mà bạn sử dụng với hàm Stop EC2 instances nhé.
Ở bước 10, trong mã nguồn (source code), chúng ta sẽ thay đổi 1 chút nhé.

  • Ở dòng ‘Name’: ‘tag:AutoOff’, bạn có thể sửa AutoOff thành tên tag mà bạn chỉ định cho server cần tự động Start.
  • Ngay dưới đó, Values thì bạn phải để là giá trị tag AutoOff bên trên mà bạn cài cho server của bạn.
  • Tiếp đến phần value của instance-state-name, bạn hãy để là stopped nhé. Vì đơn giản là bạn phải khởi động những instance mà đang ở chế độ stopped (tạm dừng) chứ nhỉ :))
  • Ở dòng 36 phía dưới cùng của đoạn code, bạn phải sửa hàm thực thi .stop() ở cuối dòng thành .start() nhé.
  • Bạn cũng có thể đổi tên biến ở dòng đó thành startingUp cũng được
  • Với dòng print ngay dưới, hãy để là print “startingUP”

Testing Lambda function

Bây giờ, chúng ta cùng test thử xem các hàm Lambda của chúng ta có chạy không nhé.

Trong giao diện Lambda console của hàm, phía trên góc bên phải của màn hình giao diện, ta nhấn vào nút Test.

Trong này, ta không cần quan tâm đến body của Test event này, chúng ta chỉ cần đặt 1 cái tên là đủ. Sau đó nhấn Save.

Sau khi Save, AWS console đưa ta quay lại với giao diện của Lambda console, ta vẫn nhấn lại vào nút Test đó lần nữa để chạy test nhé.

Nếu như giao diện hiện thông báo màu xanh như này thì chúng ta đã thiết lập thành công rồi.

Còn nếu không như trong hình ảnh bên trên thì chắc hẳn bạn đã thiết lập lỗi ở bước nào đấy rồi 🙁 Hãy kiểm tra kĩ lại nhé.

Vậy đến đây là đã xong hàm start cũng như hàm stop rồi. Giờ chúng ta cần thiết lập thời gian (event) để khởi động các hàm này nhé.

Thiết lập CloudWatch Event

1.    Trước tiên, chúng ta sẽ mở CloudWatch console. (Services -> CloudWatch)

2.    Trong cột bên trái của giao diện, dưới mục Events, chọn Rules.

3.    Ấn vàoCreate rule.

4.    Dưới phần Event Source, chọnSchedule.

5.    Làm theo 1 trong 2 cách sau đây tùy vào nhu cầu của bạn:
Chọn Fixed rate of (Tần số cố định), nhập vào 1 chu kỳ thời gian liên tục như theo phút, theo giờ, theo ngày,…
Chọn Cron expression, nhập vào 1 chuỗi định nghĩa để cho Lambda biết khi nào cần dừng (stop) EC2 instances của bạn lại. Để biết thêm thông tin chi tiết hơn về cú pháp của chuỗi định nghĩa cron expression này, bạn có thể đọc Schedule Expressions for Rules. Hoặc bạn có thể xem qua bảng sau

Note: Cron expressions được đánh giá dựa theo giờ UTC. Hãy chắc chắn rằng bạn đã tùy chỉnh nó sao cho phù hợp với múi giờ mà bạn mong muốn.

Ở đây, với mục đích ban đầu là dừng EC2 instances vào lúc 7h tối. Ta có thể cài đặt cron expression như sau: 0 19 * * ? *

6.    Ở mục Targets, chọnAdd target.

7.    ChọnLambda function.

8.    Với Function, chọn hàm Lambda function mà bạn dùng để stop EC2 instances.

9.    ChọnConfigure details.

10.   Dưới mục Rule definition, thiết lập như sau:
Với Name, nhập vào 1 cái tên tường minh, ví dụ như là “StopEC2Instances”.
(Optional) Với Description, mô tả event của bạn. Ví dụ, “Stops EC2 instances every night at 10 PM.”
Với State, tick vàoEnabled check box.

11.   Chọn Create rule.

Hãy làm tương tự với 1 Event nữa cho việc start EC2 instances vào lúc 8h sáng nhé.

Vậy là đã xong rồi đó, giờ bạn đã có thể chắc chắn rằng các EC2 instances của mình sẽ bật lên và tắt đi đúng giờ mà không chạy 1 cách lãng phí rồi :))

Tuy nhiên, chúng ta vẫn còn 1 phương pháp nữa đơn giản hơn nhiều.

2. Chỉ sử dụng CloudWatch

Có vẻ như trước đây CloudWatch chưa có cập nhật mới này, nên người dùng AWS thường xuyên phải tự tạo cho mình các hàm Lambda để tự động hóa việc Start và Stop EC2 này. Nhận thấy được nhu cầu cấp thiết đó, sau khi cập nhật, CloudWatch đã tự có cho mình tùy chọn Start & Stop EC2 instances

Chúng ta làm như sau

  1. Trước tiên, truy cập vào CloudWatch (Services -> CloudWatch)
  2. Ở cột bên trái giao diện, dưới mục Events, chọn Rules.
  3. Ấn vào Create rule.
  4. Dưới phần Event Source, chọn Schedule.
  5. Ta thiết lập thông số cho Fixed rate of hoặc Cron expression phù hợp với nhu cầu (đã nói ở bên trên).
  6. Dưới phần Targets, chọn Add target.
  7. Ở đây, ta có thể chọn các API Call phù hợp với nhu cầu của chúng ta như “EC2 StopInstances API Call” rồi nhé.

Trên đây là bài hướng dẫn 2 phương pháp để tự động hóa việc Start và Stop các EC2 instances, sau khi thực hiện thành công, ta không cần phải bận tâm về việc chạy lãng phí các server này cũng như các chi phí phát sinh sẽ được giảm đi đáng kể.

Chúc các bạn thành công! 😀