생산성 자동화

GitHub Actions로 개발 생산성 극대화: CI/CD를 넘어선 워크플로우 자동화 전략

강코의 코딩 일기 2026. 4. 28. 11:14
반응형

GitHub Actions를 활용하여 CI/CD는 물론 개발 프로세스 전반의 워크플로우를 자동화하고 생산성을 극대화하는 전략과 실제 적용 사례를 비교 분석합니다.

개발 프로젝트를 진행하면서 반복적인 수작업에 많은 시간을 할애하고 있지는 않으신가요? 코드를 빌드하고 테스트하며 배포하는 과정은 물론, 코드 리뷰, 문서 업데이트, 의존성 관리 등 개발 주기의 다양한 단계에서 반복적인 작업은 개발자에게 피로감을 주고 생산성을 저해하는 주요 원인이 됩니다. 개발 생산성 향상은 단순히 코드를 빠르게 작성하는 것을 넘어, 비효율적인 프로세스를 제거하고 개발자가 핵심 업무에 집중할 수 있는 환경을 조성하는 데서 시작합니다. 그렇다면, 이러한 반복 작업을 어디까지 자동화할 수 있을까요? 그리고 어떤 도구가 개발 프로세스 전반의 워크플로우 자동화를 효과적으로 지원할 수 있을까요?

이 글에서는 GitHub Actions를 활용하여 단순히 CI/CD(지속적 통합/지속적 배포)를 넘어선 광범위한 개발 워크플로우 자동화 전략을 심도 있게 분석하고, 이를 통해 개발 생산성을 극대화하는 방안을 제시합니다. GitHub Actions가 제공하는 유연성과 강력한 기능을 바탕으로, 개발 팀이 직면하는 다양한 문제점을 해결하고 더욱 효율적인 개발 환경을 구축하는 방법을 살펴보겠습니다.

📑 목차

GitHub Actions, 왜 특별한가?: 기존 CI/CD 툴과의 차별점 분석

GitHub Actions는 코드 저장소와 긴밀하게 통합된 CI/CD 및 워크플로우 자동화 플랫폼으로, 개발자들이 GitHub 내에서 직접 빌드, 테스트, 배포 파이프라인을 구축하고 실행할 수 있도록 지원합니다. 하지만 GitHub Actions의 진정한 강점은 단순히 CI/CD 기능을 제공하는 것을 넘어, GitHub의 방대한 생태계와 연동하여 개발 프로세스 전반을 자동화할 수 있는 유연성에 있습니다. 기존의 여러 CI/CD 툴과 비교했을 때, GitHub Actions는 몇 가지 독특한 장점을 가집니다.

클라우드 네이티브와 통합된 경험

GitHub Actions는 클라우드 기반으로 동작하며, GitHub 저장소와 완벽하게 통합되어 있습니다. 이는 별도의 서버를 구축하거나 관리할 필요 없이, YAML 파일을 통해 워크플로우를 정의하고 즉시 실행할 수 있음을 의미합니다. 코드가 푸시되거나, Pull Request가 생성되거나, 이슈가 열리는 등 GitHub에서 발생하는 다양한 이벤트에 반응하여 자동화된 작업을 트리거할 수 있습니다. 반면, 젠킨스(Jenkins)와 같은 온프레미스(On-premise) CI/CD 툴은 서버 설치 및 유지보수에 상당한 리소스가 필요하며, 클라우드 환경과의 통합은 추가적인 설정과 노력이 요구됩니다.

풍부한 액션(Actions) 마켓플레이스

GitHub Actions는 수많은 커뮤니티 및 공식 액션들을 제공하는 마켓플레이스를 보유하고 있습니다. 이를 통해 개발자들은 복잡한 스크립트를 직접 작성할 필요 없이, 이미 구현된 액션들을 조합하여 워크플로우를 손쉽게 구성할 수 있습니다. 예를 들어, 특정 언어의 환경 설정, Docker 이미지 빌드, 클라우드 플랫폼 배포, Slack 알림 등 다양한 작업을 위한 액션들이 준비되어 있습니다. 이는 워크플로우 구축에 필요한 시간을 단축하고, 일관된 품질의 자동화 스크립트를 사용할 수 있게 합니다. 다른 CI/CD 툴들도 플러그인 생태계를 가지고 있지만, GitHub Actions의 마켓플레이스는 GitHub 생태계 내에서 더욱 직관적이고 빠르게 접근할 수 있다는 장점을 가집니다.

다음 표는 GitHub Actions와 몇 가지 대표적인 CI/CD 및 자동화 툴의 특징을 비교한 것입니다.

특징 GitHub Actions Jenkins GitLab CI/CD CircleCI
설치 및 관리 클라우드 기반, GitHub 통합, 서버 관리 불필요 온프레미스/클라우드 설치, 서버 관리 필요 클라우드 기반, GitLab 통합, 서버 관리 불필요 (SaaS) 클라우드 기반, 서버 관리 불필요
워크플로우 정의 YAML 파일 (.github/workflows), 액션 조합 Groovy 기반 Pipeline 스크립트, 플러그인 YAML 파일 (.gitlab-ci.yml) YAML 파일 (.circleci/config.yml)
확장성/생태계 액션 마켓플레이스, 커뮤니티 활발 방대한 플러그인 생태계, 높은 커스터마이징 GitLab 에코시스템 내 통합 오브(Orbs)를 통한 재사용 가능한 설정
주요 강점 GitHub 저장소와의 깊은 통합, 다양한 이벤트 트리거, 강력한 워크플로우 자동화 뛰어난 유연성, 커스터마이징 가능성, 레거시 시스템 연동 용이 단일 플랫폼에서의 DevOps 통합 (코드, CI/CD, 이슈 관리 등) 빠른 빌드 속도, 쉬운 설정, 다양한 언어 지원
비용 모델 무료 사용 시간 제공 후 종량제 오픈소스, 서버 비용 발생 무료 사용 시간 제공 후 종량제 (SaaS) 무료 사용 시간 제공 후 종량제

이러한 차이점을 통해 GitHub Actions는 특히 GitHub를 주력으로 사용하는 개발 팀에게 강력한 생산성 도구로 자리매김하고 있습니다. 단순히 코드를 빌드하고 배포하는 것을 넘어, 개발 생애 주기 전반의 다양한 작업을 자동화함으로써 개발자가 코드 작성에 더 많은 시간을 할애할 수 있도록 돕습니다.

CI/CD를 넘어선 워크플로우 자동화 전략

GitHub Actions의 진정한 가치는 CI/CD 파이프라인 구축을 넘어, 개발 워크플로우의 다양한 측면을 자동화하는 데 있습니다. 단순 반복 작업을 시스템에 위임함으로써, 개발자는 창의적이고 문제 해결 중심적인 작업에 집중할 수 있게 됩니다. 여기서는 CI/CD를 넘어설 수 있는 몇 가지 워크플로우 자동화 전략을 소개합니다.

코드 품질 관리 및 정적 분석 자동화

코드 품질은 프로젝트의 유지보수성과 확장성에 직결됩니다. Pull Request(PR)가 생성될 때마다 코드 스타일 검사(Linting), 정적 분석(Static Analysis), 보안 취약점 검사 등을 자동으로 실행하여 잠재적인 문제를 조기에 발견하고 해결할 수 있습니다. 예를 들어, ESLint, Prettier, SonarQube, Bandit과 같은 툴을 GitHub Actions와 연동하여 코드 리뷰 전 자동으로 피드백을 제공함으로써, 리뷰어의 부담을 줄이고 코드 품질 기준을 일관되게 유지할 수 있습니다. 특정 규칙 위반 시 PR 병합을 차단하는 방식으로 엄격한 코드 품질 관리를 강제할 수도 있습니다.

name: Code Quality Check

on:
  pull_request:
    branches:
      - main
      - develop

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
    - name: Install dependencies
      run: npm install
    - name: Run ESLint
      run: npm run lint
    - name: Run unit tests
      run: npm test

위 예시는 Pull Request가 main 또는 develop 브랜치로 생성될 때마다 Node.js 프로젝트의 린트 검사와 단위 테스트를 자동으로 실행하는 워크플로우입니다. 이러한 자동화는 개발자가 실수로 품질 기준을 만족하지 못하는 코드를 커밋하는 것을 방지합니다.

문서화 및 번역 프로세스 자동화

문서화는 개발 프로젝트에서 간과하기 쉽지만 매우 중요한 부분입니다. 코드 변경 시 관련 문서도 함께 업데이트되어야 하지만, 수동 작업은 누락되기 쉽습니다. GitHub Actions를 사용하면 코드 변경 이벤트에 반응하여 문서 자동 생성 또는 업데이트를 트리거할 수 있습니다. 예를 들어, 특정 브랜치에 코드가 병합되면 Sphinx, MkDocs, Javadoc, Swagger UI 등의 도구를 사용하여 기술 문서를 자동으로 빌드하고 정적 웹사이트 호스팅 서비스(GitHub Pages, Netlify 등)에 배포할 수 있습니다. 다국어 프로젝트의 경우, 새로운 텍스트 추가 시 번역 플랫폼(예: Crowdin, Lokalise)과의 연동을 통해 번역 워크플로우를 자동화하여 효율적인 다국어 지원이 가능합니다.

릴리즈 노트 및 배포 관리 자동화

릴리즈 노트 작성은 시간이 많이 소요되지만 사용자에게 변경 사항을 알리는 데 필수적인 작업입니다. GitHub Actions는 커밋 메시지, Pull Request 제목 등을 기반으로 릴리즈 노트를 자동으로 생성하는 데 활용될 수 있습니다. semantic-release와 같은 도구와 연동하여 의미론적 버저닝(Semantic Versioning)에 따라 버전을 자동으로 올리고, 릴리즈 노트를 작성하며, 태그를 생성하고, 패키지를 배포하는 일련의 과정을 완전히 자동화할 수 있습니다. 이는 배포 프로세스의 일관성을 확보하고, 수동 오류를 최소화하며, 개발자의 부담을 크게 줄여줍니다.

실제 워크플로우 자동화 시나리오와 예시

이제 GitHub Actions를 활용한 실제 워크플로우 자동화 시나리오 몇 가지를 구체적인 예시와 함께 살펴보겠습니다. 이러한 예시들은 개발 팀의 생산성을 실질적으로 향상시킬 수 있는 방안을 제시합니다.

시나리오 1: Pull Request 생성 시 자동 라벨링 및 담당자 할당

규모가 큰 프로젝트에서는 매일 수많은 Pull Request가 생성됩니다. 이를 수동으로 분류하고 담당자를 할당하는 것은 비효율적입니다. GitHub Actions는 PR 제목이나 내용, 변경된 파일 경로 등을 분석하여 자동으로 라벨을 부여하고, 특정 팀 또는 개인에게 담당자를 할당할 수 있습니다.

name: Auto Label and Assign PR

on:
  pull_request:
    types: [opened, reopened, ready_for_review]

jobs:
  auto-label-assign:
    runs-on: ubuntu-latest
    steps:
    - name: Auto label based on title
      uses: actions/labeler@v4
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        sync-labels: true # .github/labeler.yml 파일을 기반으로 라벨 동기화
    - name: Assign to specific team for 'feature' PRs
      if: contains(github.event.pull_request.title, '[feat]')
      uses: actions/github-script@v7
      with:
        script: |
          github.rest.issues.addAssignees({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: context.issue.number,
            assignees: ['dev-team-leader'] // 특정 팀 리더에게 할당
          });

이 워크플로우는 PR이 열리거나 다시 열릴 때 .github/labeler.yml 파일의 규칙에 따라 자동으로 라벨을 부여하고, PR 제목에 [feat]가 포함되어 있으면 특정 담당자(dev-team-leader)를 자동으로 할당합니다. 이러한 자동화는 PR 관리의 효율성을 크게 높여줍니다.

시나리오 2: 스케줄링된 작업으로 의존성 업데이트 알림

오픈소스 라이브러리의 의존성 관리는 보안 취약점 및 기능 업데이트를 위해 중요합니다. 하지만 이를 수동으로 추적하는 것은 번거롭습니다. GitHub Actions의 스케줄링 기능을 활용하여 주기적으로 의존성 업데이트를 확인하고, 필요한 경우 알림을 보내거나 자동으로 Pull Request를 생성할 수 있습니다.

name: Dependency Update Check

on:
  schedule:
    - cron: '0 0 * * 1' # 매주 월요일 00:00 UTC에 실행

jobs:
  check-updates:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Run Dependabot (or similar tool)
      # 예시: npm-check-updates를 사용하여 업데이트 확인 및 PR 생성
      run: |
        npm install -g npm-check-updates
        ncu -u
        git diff --exit-code || (git config user.name "github-actions[bot]" && git config user.email "github-actions[bot]@users.noreply.github.com" && git add package.json package-lock.json && git commit -m "chore: update dependencies" && git push origin HEAD:dependabot-updates-branch && gh pr create --base main --head dependabot-updates-branch --title "chore: Update dependencies" --body "Automated dependency update PR.")
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

이 워크플로우는 매주 월요일에 npm-check-updates를 실행하여 package.json 파일의 의존성을 확인하고, 업데이트가 필요한 경우 자동으로 새 브랜치를 생성하고 Pull Request를 올립니다. 이는 개발 팀이 최신 상태의 의존성을 유지하고 보안 위험을 줄이는 데 기여합니다.

시나리오 3: 외부 서비스 연동을 통한 개발 경험 개선

GitHub Actions는 Slack, Jira, Trello 등 다양한 외부 서비스와의 연동을 통해 개발 경험을 개선할 수 있습니다. 예를 들어, 새로운 이슈가 생성되거나 특정 라벨이 부여될 때마다 Slack 채널에 알림을 보내거나, Jira 티켓을 자동으로 생성하는 등의 자동화가 가능합니다.

name: Notify Slack on New Issue

on:
  issues:
    types: [opened]

jobs:
  send-slack-notification:
    runs-on: ubuntu-latest
    steps:
    - name: Send Slack Notification
      uses: rtCamp/action-slack-notify@v2
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        SLACK_MESSAGE: "새로운 이슈가 열렸습니다: ${{ github.event.issue.title }}\n링크: ${{ github.event.issue.html_url }}"
        SLACK_COLOR: '#36a64f'
        SLACK_TITLE: '새로운 이슈 알림'

이 워크플로우는 GitHub에 새로운 이슈가 열릴 때마다 설정된 Slack 채널로 알림을 보냅니다. 이러한 실시간 알림 자동화는 팀원들이 중요한 이벤트에 즉시 반응하고, 정보 공유의 지연을 줄여 협업 효율성을 높이는 데 도움이 됩니다.

GitHub Actions 활용 시 고려사항 및 최적화 팁

GitHub Actions는 강력한 도구이지만, 효과적으로 활용하기 위해서는 몇 가지 고려사항최적화 팁을 알아두는 것이 중요합니다. 이는 비용 관리, 보안, 그리고 워크플로우의 효율성을 높이는 데 직결됩니다.

비용 관리 및 러너(Runner) 선택

GitHub Actions는 퍼블릭 저장소에 대해서는 무료로 무제한 사용 시간을 제공하지만, 프라이빗 저장소에 대해서는 계정 유형에 따라 일정 시간(예: Free 계정 월 2000분)을 초과하면 종량제로 비용이 발생합니다. 따라서 워크플로우의 실행 시간을 최적화하는 것이 중요합니다.

  • 불필요한 트리거 최소화: 특정 브랜치, 파일 변경 등 필요한 경우에만 워크플로우가 실행되도록 설정합니다.
  • 병렬 처리 및 캐싱 활용: 독립적인 작업은 병렬로 실행하여 전체 시간을 줄이고, 의존성 설치 등 반복적인 작업은 캐싱(caching)을 사용하여 빌드 시간을 단축합니다.
  • 적절한 러너 선택: GitHub에서 제공하는 호스팅 러너 외에, 필요에 따라 셀프 호스팅 러너(Self-hosted runner)를 구성하여 특정 환경 요구사항을 충족하거나 비용을 절감할 수 있습니다. 예를 들어, 특정 하드웨어 자원이 필요한 경우 자체 러너를 사용하는 것이 효과적입니다.

보안 베스트 프랙티스

자동화된 워크플로우는 민감한 정보(API 키, 토큰 등)에 접근할 수 있으므로, 보안은 최우선적으로 고려해야 합니다.

  • 시크릿(Secrets) 활용: 민감한 정보는 GitHub Secrets에 저장하고 워크플로우에서 안전하게 참조합니다. YAML 파일에 직접 노출하는 것을 절대 피해야 합니다.
  • 최소 권한 원칙: 워크플로우에 부여되는 권한은 필요한 최소한으로 제한합니다. permissions 키워드를 사용하여 워크플로우의 특정 작업에 대한 접근 권한을 세밀하게 제어할 수 있습니다.
  • 액션 소스 검증: 마켓플레이스에서 사용하는 액션은 신뢰할 수 있는 개발자가 제공했는지, 활발하게 유지보수되는지 확인하는 것이 좋습니다. 가능하다면 특정 버전(예: actions/checkout@v4)을 명시하여 예기치 않은 변경으로부터 보호합니다.

워크플로우 재사용 및 모듈화

복잡한 프로젝트에서는 여러 워크플로우 간에 중복되는 작업이 발생할 수 있습니다. 이를 효율적으로 관리하기 위해 워크플로우 재사용모듈화 전략을 적용할 수 있습니다.

  • 재사용 가능한 워크플로우(Reusable Workflows): 공통된 작업 흐름을 별도의 워크플로우 파일로 정의하고, 다른 워크플로우에서 호출하여 사용할 수 있습니다. 이는 코드 중복을 줄이고 일관성을 유지하는 데 매우 효과적입니다.
  • 커스텀 액션 개발: 특정 프로젝트나 조직에 특화된 복잡한 로직이 반복적으로 사용될 경우, 커스텀 액션을 직접 개발하여 재사용성을 높일 수 있습니다. 이는 JavaScript 액션 또는 Docker 컨테이너 액션 형태로 구현할 수 있습니다.
  • 템플릿 활용: 새로운 프로젝트를 시작할 때 표준화된 워크플로우 템플릿을 제공하여, 모든 팀원이 일관된 자동화 프로세스를 적용하도록 유도할 수 있습니다.

이러한 최적화 팁을 적용함으로써, GitHub Actions를 더욱 효율적이고 안전하게 활용하여 개발 생산성을 극대화할 수 있습니다.

생산성 자동화, 그 이상의 가치

GitHub Actions를 통한 개발 생산성 자동화는 단순히 반복 작업을 줄이는 것을 넘어, 개발 팀과 프로젝트 전체에 걸쳐 그 이상의 가치를 제공합니다. 이러한 가치들은 장기적으로 프로젝트의 성공과 개발자의 만족도 향상에 기여합니다.

일관성과 품질 향상

자동화된 워크플로우는 수동 작업에서 발생할 수 있는 인적 오류를 최소화하고, 모든 팀원이 일관된 절차와 기준을 따르도록 강제합니다. 예를 들어, 모든 코드 변경에 대해 동일한 린트 검사와 테스트가 실행되도록 보장함으로써, 코드 품질의 편차를 줄이고 전체적인 소프트웨어 품질을 향상시킬 수 있습니다. 이는 특히 여러 개발자가 동시에 작업하는 대규모 프로젝트에서 그 중요성이 더욱 부각됩니다.

개발자 경험(Developer Experience) 개선

반복적이고 지루한 작업에서 해방된 개발자는 더 중요한 문제 해결과 창의적인 코딩에 집중할 수 있습니다. 즉각적인 피드백 루프(예: PR 생성 시 자동 테스트 결과 제공)는 개발자가 자신의 코드를 빠르게 검증하고 수정할 수 있도록 돕습니다. 이러한 환경은 개발자의 만족도와 몰입도를 높여, 궁극적으로 팀의 전반적인 사기와 생산성 증대로 이어집니다. 개발자는 더 이상 배포 파이프라인의 복잡성에 얽매이지 않고, 핵심 비즈니스 로직 구현에 전념할 수 있습니다.

빠른 피드백 루프와 의사결정 가속화

자동화된 테스트와 검증은 코드 변경에 대한 피드백을 실시간으로 제공합니다. 이는 문제가 발생했을 때 즉시 이를 인지하고 해결할 수 있도록 하여, 문제 해결에 소요되는 시간을 대폭 단축시킵니다. 또한, 모든 변경 사항이 자동화된 검증을 거치므로, 팀원들은 더욱 신뢰할 수 있는 정보를 바탕으로 빠르게 의사결정을 내릴 수 있습니다. 예를 들어, 자동화된 배포는 새로운 기능을 더 자주, 더 안전하게 릴리즈할 수 있게 하여 시장 변화에 대한 대응력을 높입니다.

확장성과 유지보수성 증대

잘 구축된 GitHub Actions 워크플로우는 프로젝트의 성장에 따라 쉽게 확장될 수 있습니다. 새로운 서비스가 추가되거나, 새로운 기술 스택이 도입되더라도, 기존의 자동화 프레임워크 내에서 새로운 워크플로우를 추가하거나 기존 워크플로우를 수정하는 방식으로 유연하게 대응할 수 있습니다. 이는 장기적인 관점에서 프로젝트의 유지보수 비용을 절감하고, 기술 부채의 축적을 방지하는 데 기여합니다. 재사용 가능한 액션워크플로우 템플릿은 이러한 확장성을 더욱 강화하는 요소입니다.

결과적으로, GitHub Actions를 통한 생산성 자동화는 개발 팀이 기술적 우위를 확보하고, 더욱 혁신적인 솔루션을 만들어내는 데 필수적인 기반을 제공합니다. 이는 단순한 도구의 활용을 넘어, 개발 문화와 프로세스 전반의 긍정적인 변화를 이끌어내는 전략적 투자라고 할 수 있습니다.

결론: GitHub Actions로 열어가는 개발의 미래

지금까지 GitHub Actions를 활용하여 CI/CD를 넘어선 광범위한 개발 워크플로우 자동화 전략과 그 실제 적용 사례, 그리고 최적화 방안에 대해 심도 있게 살펴보았습니다. GitHub Actions는 단순히 코드를 빌드하고 배포하는 도구를 넘어, 개발 생애 주기 전반의 반복적인 작업을 자동화하여 개발 팀의 생산성을 극대화하는 강력한 플랫폼입니다.

GitHub 저장소와의 깊은 통합, 풍부한 액션 마켓플레이스, 그리고 유연한 워크플로우 정의 기능은 개발자들이 코드 품질 관리, 문서화, 릴리즈 관리 등 다양한 영역에서 자동화된 프로세스를 구축할 수 있도록 지원합니다. 이를 통해 개발자는 지루하고 반복적인 작업에서 벗어나, 더욱 창의적이고 가치 있는 문제 해결에 집중할 수 있게 됩니다. 이는 개발자 경험을 향상시키고, 프로젝트의 일관성과 품질을 높이며, 궁극적으로 더 빠르고 안정적인 소프트웨어 개발을 가능하게 합니다.

GitHub Actions는 DevOps 문화를 효과적으로 구현하고, 자동화를 통해 개발 팀의 역량을 한 단계 끌어올리는 데 필수적인 도구입니다. 아직 GitHub Actions의 잠재력을 충분히 활용하지 못하고 있다면, 지금 바로 팀의 워크플로우를 분석하고 자동화 전략을 수립해 보시기 바랍니다. 작은 자동화 하나하나가 모여 개발 프로세스 전반의 혁신을 가져올 것입니다.

여러분의 프로젝트에서는 GitHub Actions를 어떻게 활용하고 계신가요? CI/CD를 넘어선 특별한 자동화 경험이나 이 있다면 댓글로 공유해 주세요. 함께 더 나은 개발 문화를 만들어갈 수 있기를 기대합니다.

📌 함께 읽으면 좋은 글

  • [생산성 자동화] Git Hooks로 개발 생산성 극대화: 로컬에서 코드 품질과 자동화 구축 전략
  • [커리어 취업] 개발자 연봉 협상 성공 전략: 시장 가치 파악부터 제안 수락까지
  • [커리어 취업] 비전공 개발자 성공적인 커리어 전환 전략: 현실적인 준비부터 취업까지

이 글이 도움이 되셨다면 공감(♥)댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.

반응형