지난 시간에 이어서 Lambda로 EC2를 컨트롤해 보자.
인스턴스를 시작하고 중지하는 방법은 1편에서 만나볼 수 있다.
2편에서는 이렇게 시작/중지가 가능해진 인스턴스에 쉘 스크립트를 직접 전달해 볼 것이다.
보통 외부에서 인스턴스에 접근하려면 SSH를 많이 사용하지만,
이번에는 SSM이라는 AWS의 관리형 서비스를 이용할 것이다.
간단히 요약하자면 Lambda 함수에서 스크립트를 Systems Manager에 전달하고, 이를 다시 인스턴스에 넘겨주는 방식.
1편보다 좀 더 복잡한 내용이므로 차근차근 따라와 주기 바란다.
일단 Lambda함수가 SSM을 컨트롤할 수 있도록 적절한 정책을 만든다.
lambda-ssm이라는 정책을 아래와 같이 선언하였다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ssm:SendCommand",
"iam:PassRole",
"ssm:CreateAssociation",
"ssm:GetDocument",
"ssm:ListDocuments",
"ssm:ListAssociations",
"ssm:CreateDocument"
],
"Resource": "*"
}
]
}
이렇게 만들어진 정책을 역할에 할당한다.
다음으로 EC2가 SSM으로부터 명령을 받아올 수 있도록 또 다른 역할을 구성한다.
이번에는 기본 정책 중에서 AmazonEC2RoleforSSM
을 선택한다.
IAM 세팅은 이렇게 마무리한다.
이어서 스크립트를 실행하는 함수를 만든다.
1편과 마찬가지로 boto3 레이어가 필요하며, python 3.9환경을 기준으로 서술한다.
먼저 boto3를 로드한다.
import boto3
이어서 각 서비스 개체들을 정의한다. EC2와 SSM을 사용할 것이기 때문에 두 가지를 모두 정의해야 한다.
def define_instances(self):
self.ec2=boto3.client("ec2",region_name='ap-northeast-2')
self.ssm=boto3.client("ssm")
다음으로 실행할 스크립트를 정의한다.
def set_script(self, taskname):
"""
태스크별 스크립트 세팅
Args:
taskname (str): 태스크 유형
- test: 테스트 스크립트
- main: 메인 태스크 실행
- delete: 메인 태스크 실행 후 생성된 엑셀 파일 삭제
"""
if taskname=='test':
self.script=[
'echo "Hello World!" > /home/ec2-user/helloword.txt'
]
elif taskname=='listing':
self.script=[
'python3 /home/ec2-user/l_module.py'
]
elif taskname=='search':
self.script=[
'python3 /home/ec2-user/n_module.py'
]
elif taskname=='main':
self.script=[
'sudo python3 /home/ec2-user/Main.py'
]
elif taskname=='delete':
self.script=[
'sudo find . -name "*.xlsx" -delete'
]
참고로 스크립트는 인스턴스로 바로 전달되는 것이 아니라 SSM을 통해서 전달되며, 따라서 별도의 디렉토리 세팅을 하지 않는 이상 사용자 경로가 아닌 루트 경로에서부터 명령어를 작성해야 하는 점 유의하기 바란다.
또 스크립트를 여러 줄 사용하고 싶을 경우 문자열 안에서 \n
으로 구분하거나, 혹은 리스트에 문자열을 추가해 주어도 된다.
스크립트를 준비했다면 이 스크립트를 실행하는 function을 정의한다.
def run_script(self, id):
for line in self.script: #스크립트를 리스트로 여러 개 정의하는 경우에 대비
print(line) #스크립트 출력
self.ssm.send_command(
DocumentName='AWS-RunShellScript',
Parameters={'commands':[line]}, #반드시 리스트로
InstanceIds=[id] #반드시 리스트로
)
참고로 이 함수들을 아우르는 __main__
함수는
def __main__(self):
self.define_instances()
self.set_script(taskname='search')
self.run_script(id='i-************')
이렇게 되어 있다.
또 런타임 유형을 스크립트 실행이 가능하도록 좀 더 넉넉하게 잡아 주자. 나의 경우는 일부러 좀 더 넉넉하게 잡아 뒀는데, 테스트 결과 한 줄 스크립트를 전달하려면 10초 정도의 시간을 주면 충분한 것 같다.
세팅을 마쳤다면 앞에서 만들어 둔 역할을 연결해 준다.
1편에서 인스턴스가 준비되었다는 것을 전제로 설명을 진행한다.
일단 나의 경우 파이썬 파일을 실행하는 것이 목적이기 때문에, 각 인스턴스의 볼륨에다가 py 파일들을 넣어 두었다. 각 파일의 용도와 기능은 여기서 언급하지 않겠다.
타겟팅할 인스턴스에도 만들어 둔 IAM 역할을 연결한다.
EC2에서 권한 설정을 올바르게 했다면, SSM의 Fleet Manager로 이동하여 해당 인스턴스가 표시되는지, 즉 관리형 노드로 설정되어 있는지 확인한다. 타겟 인스턴스가 정상적으로 노출된다면 SSM으로부터 스크립트를 받아올 수 있다는 의미이다.
이렇게 Lambda-SSM-EC2 간의 연결까지 모두 마치면 스크립트를 전송할 준비가 끝난다. 실무에 적용하기 전 echo "Hello World"
와 같은 간단한 스크립트를 통해 테스트를 수행해 보자.