개인 프로젝트 도중 비용 문제 때문에 개발 도중 EC2가 자주 내려가는 상황에서 EC2를 매번 실행하고 RDS와 Airflow를 따로 접속하여 실행해주는 과정이 매우 귀찮기 때문에 이를 자동화하는 과정을 정리하였습니다.
Systemd
먼저 Linux 환경에는 systemd라는 것이 존재합니다. systemd는 시스템 및 서비스 관리자로 저희가 원하는 부팅시 할 작업에 대해 정의할 수도 있습니다.
Systemd는 "유닛"이라는 개념을 사용하여 서비스를 관리합니다. 유닛 파일은 .service
, .socket
, .mount
등 여러 유형이 있으며, 각 유닛 파일은 서비스를 어떻게 관리할지에 대한 정보를 담고 있습니다.
예를 들어, nginx.service
유닛 파일은 Nginx 웹 서버의 설정과 동작을 정의합니다.
또한 리눅스 명령창에서 아래 명령들을 통해 여러 서비스 관련 작업이 가능합니다.
# 서비스 상대 확인
systemctl status [서비스명]
# 서비스 시작
systemctl start [서비스명]
# 서비스 중단
systemctl stop [서비스명]
# 부팅시 실행할 서비스 등록
systemctl enable [서비스명]
# 로그 조회
journalctl -u [서비스명]
...
이를 통하여 EC2가 실행 될 때 RDS와 Airflow를 실행시켜봅시다.
EC2 실행시 RDS 실행 자동화 하기
RDS 자동 실행을 위한 전체 과정은 다음과 같습니다.
- RDS 실행 자동화 Lambda 함수 생성
- EC2에 위 Lambda 함수를 실행하는 Bash 스크립트 작성
- 이때 AWS CLI 사용
- EC2 systemctl에 위 bash 스크립트를 실행하는 서비스 생성 및 부팅시 실행하도록 설정
Lambda 함수 작성
먼저 RDS 실행 자동화를 위한 Lambda 함수는 다음과 같이 boto3를 사용하는 코드를 작성할 수 있습니다.
import boto3
import json
def rds_start_by_lambda(event, context):
rds_tag_key = "tag key"
rds_tag_value = "tag value"
result = {"statusCode": 200, "body": {"instances": []}}
rds_client = boto3.client("rds", region_name="my-rds-region")
try:
db_instances = rds_client.describe_db_instances()["DBInstances"]
for rds in db_instances:
# Jun-1 팀의 RDS인지 확인하는 변수
not_my_rds = True
# Tag로 체크하기
for item in rds["TagList"]:
if item["Key"] == rds_tag_key and item["Value"] == rds_tag_value:
not_my_rds = False
if not_my_rds:
continue
instance_id = rds["DBInstanceIdentifier"]
status = rds["DBInstanceStatus"]
instance_info = {"InstanceID": instance_id, "Status": status}
print(f"instance_id: {instance_id} status: {status}")
if status != "available":
rds_client.start_db_instance(DBInstanceIdentifier=instance_id)
print(f"RDS instance {instance_id} is being started")
instance_info["Action"] = "Started"
else:
print(f"RDS instance {instance_id} is already started")
instance_info["Action"] = "Already Running"
result["body"]["instances"].append(instance_info)
if not result["body"]["instances"]:
result["statusCode"] = 404
result["body"]["message"] = "No RDS instances found with the specified tag."
return json.dumps(result)
except Exception as e:
print(f"Error occured!! {str(e)}")
return {"statusCode": 500, "body": json.dumps({"message": f"Error {str(e)}"})}
그냥 단순히 Tag로 달아준 것과 일치하는 RDS를 실행하는 함수입니다.
EC2에 위 Lambda 함수를 실행하는 Bash 스크립트 작성
이제 위 Lambda 함수를 실행하는 Bash 스크립트를 작성해야합니다.
이를 작성하기 전 AWS의 Lambda를 실행해야하므로 AWS CLI를 설치해주어야 합니다.
https://inpa.tistory.com/entry/AWS-📚-AWS-CLI-설치-사용법-쉽고-빠르게#cli_인증_설정
[AWS] 📚 AWS CLI 설치 & 등록 방법 - 쉽고 빠르게 설명
AWS CLI (Command Line) AWS Command Line Interface는 쉘 커맨드를 사용하여 AWS 서비스와 상호 작용할 수 있는 도구이다. 우리가 브라우저로 아마존 웹 서비스 홈페이지(콘솔 홈)에 가서 서비스를 이용한 것
inpa.tistory.com
위 블로그를 참조해보면 다음과 같이 설치할 수 있습니다.
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
$ aws --version
aws-cli/2.7.9 Python/3.9.11 Linux/5.13.0-51-generic exe/x86_64.ubuntu.20 prompt/off
$ rm -f awscliv2.zip # 설치 되었으면 zip은 지워주자. 용량이 여유롭지 못하다
이후 AWS 계정 인증을 해야합니다. 이미 IAM 사용자와 엑세스키를 만들어 놓았기 때문에 이를 활용해 간단히 할 수 있습니다.
Bash 창에 aws configure
를 입력 후 액세스 키 정보를 넣고 사용할 리전을 추가합니다.
$ aws configure
AWS Access Key ID [None] : [발급받은 IAM의 Access Key ID]
AWS Secret Access Key [None] : [발급받은 IAM의 Secret Access Key]
Default region name [None] : ap-northeast-2[서울 리전]
Default output format [None] : text / json / table
위 내용을 참조하면 좋습니다.
이후 Lambda 함수를 실행하는 스크립트를 작성합니다. /home/ubuntu/call_lambda.sh
#!/bin/bash
LAMBDA_FUNCTION_NAME="jun-1-rds-auto-start-lambda"
aws lambda invoke --function-name "$LAMBDA_FUNCTION_NAME" /tmp/lambda_response.json
cat /tmp/lambda_response.json >> /var/log/call_lambda.log
이를 실행시 AWS Lambda를 실행할 수 있습니다. 그렇기 때문에 실행을 할 수 있는 파일로 만들어야 하니 아래 명령어를 통해 실행할 수 있는 파일로 만들어 줍니다.
chmod 700 call_lambda.sh
chmod는 파일 권한을 설정하는 명령어로 3자리 수로 권한을 설정합니다.
각 수는 8진수로 rwx → 읽기, 쓰기, 실행 권한에 대한 허용을 가리킵니다.
즉, 7(111)인 경우 모든 권한을 부여하고, 4(100)인 경우 읽기 권한만 부여합니다.
또한 각 수는 소유자 권한, 그룹 권한, 기타 사용자 권한입니다.
그러므로 위와 같은 chmod 700은 소유자만 모든 권한을 가지고 나머지 사용자는 아무런 권한이 없게 됩니다.
위 Lambda 실행 스크립트를 systemd에서 부팅시 실행해주기
이제 마지막으로 systemd를 추가해주면 됩니다.
/lib/systemd/system/rds_auto_start.service
를 아래와 같이 만듭니다.
[Unit]
Description=Call AWS Lambda Function for RDS Start
After=network.target
[Service]
ExecStart=/home/ubuntu/call_lambda.sh
User=ubuntu
Group=ubuntu
Type=oneshot
[Install]
WantedBy=multi-user.target
이때 위와 같이 service 유닛 파일은 [Unit], [Service], [Install] 3가지 섹션으로 이루어져 있습니다. 이들에 대해 간단히 정리해보면 다음과 같습니다.
- [Unit]: 유닛의 일반적 정보를 정의. 언제 어떻게 시작할지에 대한 정보
- [Service]: 실제 서비스의 동작을 정의
- [Install]: 유닛의 설치와 관련된 설정을 정의
더욱 자세한 내용은 아래 블로그 참조
https://bakery-it.tistory.com/7
systemd service file
systemd unit 중 service 파일의 구성 (unit 에는 service 외에도 socket, 등 다양하게 있다.) https://www.freedesktop.org/software/systemd/man/systemd.unit.html https://www.freedesktop.org/software/systemd/man/systemd.service.html Unit 파일
bakery-it.tistory.com
이후 아래 명령어를 통해 EC2 시작시 실행되도록 해줍니다.
sudo systemctl daemon-reload
sudo systemctl enable rds_auto_start_lambda.service
이제 서버를 내렸다 올려보면 RDS를 자동 체크하며 실행하는 것을 확인할 수 있습니다.
Airflow 자동 실행하기
이전과 마찬가지로 systemd에 service를 등록해야합니다.
/lib/systemd/system/airflow.service
를 아래와 같이 작성합니다.
[Unit]
Description=Airflow docker compose up when ec2 started
Requires=docker.service
After=rds_auto_start_lambda.service
After=network.target
[Service]
WorkingDirectory=/home/ubuntu/airflow-docker
ExecStart=docker compose up -d
ExecStop=docker compose down
Restart=on-failure
User=ubuntu
RemainAfterExit=yes
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
위 스크립트는 docker 서비스와 rds_auto_start_lambda 서비스가 완료된 후 실행됩니다.
이때 /home/ubuntu/airflow-docker
폴더에서 Service를 실행하며 이때 docker compose up -d
를 통하여 백그라운드에서 airflow를 실행합니다.
이때 중요한 점으로 RemainAfterExit=yes
로 두어 완료 후 탈출하지 않고 대기하며, TimeoutStartSec=0
으로 두어 무제한으로 대기하게 해야합니다. (아니면 실패하더라구요)
sudo systemctl daemon-reload
sudo systemctl enable airflow.service
sudo systemctl start airflow.service
이후 이전처럼 service로 등록해줍니다.
만약 서버를 재실행 하고싶다면 아래 명령어를 입력하면 됩니다.
sudo systemctl restart airflow.service
Reference
'공부 및 정리 > 기타 정리' 카테고리의 다른 글
ChatGPT API 비용 감축하기 (0) | 2024.07.29 |
---|---|
Private RDS에 Local Airflow에서 접근하기 (2) | 2024.07.24 |
Github Actions를 사용한 꺼진 AWS Instance에도 CI/CD하기 (1) | 2024.07.23 |
AWS EMR을 활용한 Spark 클러스터 서버 구축 (0) | 2024.06.24 |
Github Action을 통해 좋아하는 블로그의 새 포스팅 자동 알림 만들기 (8) | 2024.05.29 |