Atlassian Statuspage 도입과 자동화 적용기

Atlassian Statuspage 도입과 자동화 적용기

도입

Why you need a status page - Work Life by Atlassian
A status page is an essential part of any incident communication strategy; they can can turn negative customer experiences into positive ones.
우리가 statuspage를 운영해야 하는 이유에 대해..

많은 서비스들이 장애 발생과 해결 상태 공유를 그 사용자들에게 공유하기 위해 status 표시 페이지를 많이 사용하고 있다. Status page 운영을 위한 여러 오픈소스들과 옵션들이 있지만 Atlassian statuspage를 선택한 건 아래의 이유다.

  • 조직 내에서 Jira를 사용하고 있으며, 이와의 연동이 매우 훌륭하다.
  • Slack 노티피케이션 설정이 간단하다.
  • Datadog 으로부터 메트릭을 활용할 수도 있다.

여러 플랜 중 제일 저렴한 hobby plan으로도 충분하다고 봤다. 결제 이후 커스터마이즈는 매우 쉽다.

서비스의 디자인 언어와 최대한 싱크를 맞추려고 커스터마이징도 했다.

저비용으로 Health-check API를 자동화해보자.

내가 회사에서 개발하고 운영 중인 서비스들은 Health Check API를 노출하고 있다. 이 엔드포인트를 주기적으로 요청하여 서비스 상태에 이상이 있을 경우 statuspage 에 노출시키도록 하였다.

Statuspage API Documentation
Welcome to Statuspage’s API! The Statuspage API empowers developers to automate, extend and combine Statuspage with other services.

HTTP API를 제공하기 때문에 손쉽게 statuspage에 에러 보고를 할 수 있었다.

github actions

name: "Status check every hour"
on:
  schedule:
    - cron:  "*/30 * * * *"
  workflow_dispatch:

jobs:
  status_check:
    name: Run Status check
    runs-on: ubuntu-latest
    steps:

      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false
          fetch-depth: 0

      - name: Set up Python environment
        uses: actions/setup-python@v2.3.1
        with:
          python-version: "3.9"

      - name: Install requirements
        run: pip install -r requirements.txt

      - name: RUN HEALTHCHECK
        run: python main.py
        env:
          STATUSPAGE_API_TOKEN : ${{ secrets.STATUSPAGE_API_TOKEN }}

main program

from datetime import datetime
import json
from os import environ

from requests import Response, Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry


retry = Retry(
    total=3,
    read=3,
    connect=3,
    backoff_factor=0.3,
    status_forcelist=(500, 502, 504),
)
adapter = HTTPAdapter(max_retries=retry)

session = Session()
session.mount('http://', adapter)
session.mount('https://', adapter)

with open('data.json', 'r') as fp:
    data = json.load(fp)

PAGE_ID = data.get('page').get('id')
STATUSPAGE_API_TOKEN = environ.get('STATUSPAGE_API_TOKEN')


def check_statuspage_api_status():
    response = session.get(
        headers={'Authorization': f'OAuth {STATUSPAGE_API_TOKEN}'},
        url=f'https://api.statuspage.io/v1/pages/{PAGE_ID}.json'
    )
    response.raise_for_status()
    print('[INFO] STATUSPAGE API STATUS CHECK OK')


def report_incident(component_api_id: str) -> None:
    body = {
        "incident": {
            "name": "API Health check가 실패합니다.",
            "impact": "critical",
            "impact_override": "critical",
            "created_at": datetime.now().isoformat(),
            "body": "자동화된 Health Check API 요청이 실패하였습니다. 개발팀이 조사하고 있습니다.",
            "component_ids": [component_api_id],
            "components": {
                component_api_id: "partial_outage"
            }
        }
    }
    session.post(
        headers={'Authorization': f'OAuth {STATUSPAGE_API_TOKEN}'},
        json=body,
        url=f'https://api.statuspage.io/v1/pages/{PAGE_ID}/incidents'
    )


def health_check(url: str, component_api_id: str) -> bool:
    response: Response = session.get(url=url, timeout=3)

    print(f'[INFO] check result: {url} {"OK" if response.ok else "FAIL"}')

    if not response.ok:
        report_incident(component_api_id=component_api_id)


if __name__ == '__main__':
    check_statuspage_api_status()
    for item in data.get('components'):
        health_check(
            url=item.get('health_check_url'),
            component_api_id=item.get('component_api_id')
        )
사용 중인 코드의 일부

Private Subnets 안에 있는 리소스들도 github actions self-hosted runner 기능을 이용한다면, 무리없이 작업에 포함시킬 수 있을 것이다.

GitHub - machulav/ec2-github-runner: On-demand self-hosted AWS EC2 runner for GitHub Actions
On-demand self-hosted AWS EC2 runner for GitHub Actions - GitHub - machulav/ec2-github-runner: On-demand self-hosted AWS EC2 runner for GitHub Actions

알림 설정

모든 멤버들이 사용하는 슬랙에 알림을 걸었다. 실시간으로 잘 오는 것을 여러 번 확인했다. 이를 통한 빠른 대응, Statuspage가 제공해주는 Post-mortem 기능과 함께 더 안정적인 서비스를 운영할 수 있어보인다.