글을 작성하게 된 계기
프로젝트를 하면서 Github Action이 실행되면 남는 Workflow를 자동으로 삭제하고 싶었습니다. 이 과정에서 어떤 점을 고려했고, 어떻게 자동화를 했는지 과정을 기록하기 위해 글을 작성하게 되었습니다.
1. 문제 상황
프로젝트에서 Github Action을 사용한 후 Workflow를 수동 으로 삭제하고 있었습니다. 하지만 매번, 이 과정을 반복하는 것이 꽤 번거로웠는데요, 현재 테스트 자동화 가 돼 있다 보니 하루에 수십 번씩 테스트 코드가 실행 되었기 때문입니다.
즉, Workflow가 너무 많이 남아서 이를 수동으로 삭제하는 것이 꽤 힘든 상황이었고, 이를 자동화 하고 싶었습니다.
아래와 같은 몇 가지 선택지가 있었는데, 이 중 AWS 서비스를 활용 하기로 결정했습니다.
- Github Action 스케줄러 활용
- CI/CD 활용
- 코드로 스케줄러 구현
- AWS 서비스 활용
1번은 Github Action의 스케줄러가 딜레이가 있기 때문에 배제했습니다. 정확한 시간이 중요한 기능은 아니지만, 기본적으로 스케줄링은 내가 원할 때 실행할 수 있으면 했기 때문입니다.
The schedule event can be delayed during periods of high loads of GitHub Actions workflow runs.
2번은 Workflow는 일정 주기 마다 삭제하면 되는 기능인데 매 번 실행될 필요가 없어 배제했고, 3번은 부가적인 기능을 구현하기 위해 애플리케이션에 코드를 추가할 필요는 없어보여 배제했습니다.
Github Action 스케줄러: 딜레이가 있어서 내가 완벽히 제어하지 못해서 배제CI/CD: 일정 주기마다 삭제하면 되는 기능을 매 번 실행할 필요가 없어서 배제코드로 스케줄러 구현: 부가적인 기능을 구현하기 위해 애플리케이션에 코드를 추가할 필요가 없어서 배제
결론적으로 Eventbridge, SNS, Lambda 와 같은 AWS 서비스를 활용해 Workflow를 삭제하도록 결정했습니다. 내가 원하는 시간에 주기적으로 실행할 수 있고, 애플리케이션에는 코드가 추가되지 않으며, 비용도 거의 없기 때문입니다.
- 내가 원하는 시간에 주기적으로 실행 가능
- 애플리케이션에 코드가 추가되지 않음
- 비용 부담이 거의 없음
2. 문제 해결
문제 해결 플로우는 다음과 같습니다. AWS Eventbridge로 일정 시간마다 트리거를 당긴 후, SNS를 거쳐 람다를 실행하는 것입니다. SNS는 선택사항으로 불필요하면 빼셔도 상관없습니다.
AWS 서비스를 어떻게 사용하는지는 생략하겠습니다. Lambda 코드를 살펴보면 다음과 같은데, 저는 간단히 파이썬을 사용했지만, 본인이 편한 언어를 사용하면 됩니다. Eventbridge가 트리거를 당기면 Github API를 호출해 Workflow의 ID를 조회한 후, 하루가 지난 Workflow를 삭제하는 코드입니다.
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
def lambda_handler(event, context):
# 환경 변수에서 GitHub 액세스 토큰, 레포지토리
token = os.getenv("github_token")
repo = os.getenv("repo")
# 하루 전 날짜 계산
yesterday = (datetime.utcnow() - timedelta(days=1)).isoformat() + "Z"
# GitHub API 요청
headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
# Workflow 실행 ID 목록 가져오기
response = requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=100",
headers=headers
)
if response.status_code == 200:
workflow_runs = response.json().get("workflow_runs", [])
for run in workflow_runs:
run_id = run["id"]
created_at = run["created_at"]
# 하루 전 기록 삭제
if created_at < yesterday:
delete_response = requests.delete(
f"https://api.github.com/repos/{repo}/actions/runs/{run_id}",
headers=headers
)
if delete_response.status_code == 204:
print(f"Deleted workflow run {run_id}")
else:
print(f"Failed to delete run {run_id}: {delete_response.status_code}")
else:
print(f"Failed to retrieve workflow runs: {response.status_code}")
구현하고 보니 추가로 로컬에서만 이를 실행하는 방법도 생각이 났는데요, 이 경우, 다음과 같은 쉘 스크립트를 작성할 수도 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# GitHub 개인 액세스 토큰 설정
TOKEN="${GITHUB_TOKEN}"
REPO="${REPO}"
# 하루 전 날짜 계산 (macOS 호환)
if [[ "$OSTYPE" == "darwin"* ]]; then
YESTERDAY=$(date -v -1d +%Y-%m-%dT%H:%M:%SZ)
else
YESTERDAY=$(date -d "1 day ago" +%Y-%m-%dT%H:%M:%SZ)
fi
# 하루가 지난 워크플로 기록 삭제
for run_id in $(curl -s -H "Authorization: token $TOKEN" \
"https://api.github.com/repos/$REPO/actions/runs?per_page=100" | \
jq -r --arg yesterday "$YESTERDAY" '.workflow_runs[] | select(.created_at < $yesterday) | .id'); do
echo "Deleting workflow run $run_id"
curl -X DELETE -H "Authorization: token $TOKEN" \
"https://api.github.com/repos/$REPO/actions/runs/$run_id"
done
매번 실행되지 않아도 되는 기능이기 때문에 이 정도 방법만으로도 충분할 것으로 보였습니다. 자동화할 때, 항상 사람이 신경 쓰지 않도록 하는 것만 고려했는데, 자동화 비용, 만든 후의 유지보수 비용 까지 생각하면 굳이 외부 서비스를 사용해야 할까? 에 대해 한번 생각해 본 계기가 되었네요.
3. 정리
AWS 서비스를 활용해 간단한 자동화를 했는데, 이를 통해 수동으로 수십 페이지씩 수동으로 삭제하던 작업을 더 이상 하지 않아도 되었습니다. 자동화는 언제나 즐거운데요, 다만, 이번 일을 통해 자동화 비용, 유지보수 비용 에 대해서도 한 번 더 생각해볼 수 있는 계기가 됐던 것 같습니다.
추가로 Github에서 제공하는 API가 많던데, 이를 잘 활용하는 방법도 조금 더 살펴봐야겠네요.