# CircleCI에서 GitHub Actions 마이그레이션

GitHub Actions 및 CircleCI는 구성에서 몇 가지 유사점을 공유하므로 GitHub Actions 마이그레이션이 비교적 간단합니다.

## 소개

CircleCI 및 GitHub Actions를 사용하면 코드를 자동으로 빌드하고 테스트하고 게시하고 릴리스하고 배포하는 워크플로를 만들 수 있습니다. CircleCI 및 GitHub Actions는 워크플로 구성에서 몇 가지 유사점을 공유합니다.

* 워크플로 구성 파일은 YAML로 작성되며 리포지토리에 저장됩니다.
* 워크플로에는 하나 이상의 작업이 포함됩니다.
* 작업에는 하나 이상의 단계 또는 개별 명령이 포함됩니다.
* 단계 또는 작업을 다시 사용하고 커뮤니티와 공유할 수 있습니다.

자세한 내용은 [GitHub Actions에 대한 이해](/ko/actions/learn-github-actions/understanding-github-actions)을(를) 참조하세요.

## 주요 차이점

CircleCI에서 마이그레이션하는 경우 다음과 같은 차이점을 고려하세요.

* CircleCI의 자동 테스트 병렬 처리는 사용자가 지정한 규칙 또는 기록 타이밍 정보에 따라 테스트를 자동으로 그룹화합니다. 이 기능은 GitHub Actions에 기본 제공되지 않습니다.
* 컨테이너의 사용자 매핑이 다르기 때문에 Docker 컨테이너에서 실행되는 작업은 권한 문제에 민감합니다.
  `USER` 명령을 \_Dockerfile\_에서 사용하지 않으면 많은 문제를 방지할 수 있습니다. GitHub 호스팅 실행기의 Docker 파일 시스템에 대한 자세한 내용은 [GitHub 호스팅 실행기](/ko/actions/using-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem)을(를) 참조하세요.

## 워크플로 및 작업 마이그레이션

CircleCI는 `workflows` 파일에서 \_\_ 를 정의합니다. 이를 통해 둘 이상의 워크플로를 구성할 수 있습니다. GitHub에는 워크플로당 하나의 워크플로 파일이 필요하므로 `workflows`를 선언할 필요가 없습니다.
\_config.yml\_에 구성된 각 워크플로에 대한 새 워크플로 파일을 만들어야 합니다.

CircleCI와 GitHub Actions는 비슷한 구문을 사용하여 구성 파일에서 `jobs`를 구성합니다. CircleCI 워크플로에서 `requires`를 사용하는 작업 간의 종속성을 구성하는 경우 해당 GitHub Actions `needs` 구문을 사용할 수 있습니다. 자세한 내용은 [GitHub Actions에 대한 워크플로 구문](/ko/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds)을(를) 참조하세요.

## 작업으로 orbs 마이그레이션

CircleCI 및 GitHub Actions는 워크플로에서 작업을 재사용하고 공유하는 메커니즘을 제공합니다. CircleCI는 YAML로 작성된 orbs라는 개념을 사용하여 워크플로에서 다시 사용할 수 있는 작업을 제공합니다. GitHub Actions에는 JavaScript 파일 또는 Docker 이미지로 빌드하는 작업이라는 강력하고 유연하며 재사용 가능한 구성 요소가 있습니다. GitHub의 API와 공개적으로 사용할 수 있는 타사 API와의 통합을 포함하여 원하는 방식으로 리포지토리와 상호 작용을 하는 사용자 지정 코드를 써서 작업을 만들 수 있습니다. 예를 들어 작업은 npm 모듈을 게시할 수 있고 긴급한 이슈가 발생할 때 SMS 알림을 보낼 수 있으며 프로덕션 준비 코드를 배포할 수 있습니다. 자세한 내용은 [자동화 재사용](/ko/actions/creating-actions)을(를) 참조하세요.

CircleCI는 YAML 앵커 및 별칭을 사용하여 워크플로 부분을 다시 사용할 수 있습니다. GitHub Actions는 재사용성을 위해 YAML 앵커와 별칭을 지원하고, 다양한 구성으로 작업을 실행하기 위한 매트릭스도 제공합니다. 행렬에 대한 자세한 내용은 [워크플로에서 작업 변형 실행](/ko/actions/using-jobs/using-a-matrix-for-your-jobs)을(를) 참조하세요.

## Docker 이미지 사용

CircleCI 및 GitHub Actions는 Docker 이미지 내부의 실행 단계를 지원합니다.

CircleCI는 일반적인 종속성이 있는 미리 빌드된 이미지 집합을 제공합니다. 해당 이미지에는 `USER`가 `circleci`로 설정되어 있으며 이로 인해 사용 권한이 GitHub Actions와 충돌합니다.

GitHub Actions로 마이그레이션할 때는 CircleCI의 미리 빌드된 이미지를 사용하지 않는 것이 좋습니다. 대부분의 경우 작업을 사용하여 필요한 추가 종속성을 설치할 수 있습니다.

Docker 파일 시스템에 대한 자세한 내용은 [GitHub 호스팅 실행기](/ko/actions/using-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem)을(를) 참조하세요.

GitHub 호스팅 실행기 이미지에서 사용할 수 있는 도구 및 패키지에 대한 자세한 내용은 [GitHub 호스팅 실행기](/ko/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software)을(를) 참조하세요.

## 변수 및 비밀 사용

CircleCI와 GitHub Actions는 구성 파일에서 환경 변수를 설정하고 CircleCI나 GitHub UI를 사용하여 비밀을 생성할 수 있습니다.

자세한 내용은 [변수 참조](/ko/actions/reference/variables-reference#default-environment-variables) 및 [GitHub Actions에서 비밀 사용](/ko/actions/security-guides/using-secrets-in-github-actions)을(를) 참조하세요.

## 캐싱

CircleCI 및 GitHub Actions는 구성 파일에서 파일을 수동으로 캐시하는 메서드를 제공합니다.

다음은 각 시스템에 대한 구문의 예입니다.

### 캐싱을 위한 CircleCI 구문

```yaml
- restore_cache:
    keys:
      - v1-npm-deps-{{ checksum "package-lock.json" }}
      - v1-npm-deps-
```

### 캐싱에 대한 GitHub Actions 구문

```yaml
- name: Cache node modules
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: v1-npm-deps-${{ hashFiles('**/package-lock.json') }}
    restore-keys: v1-npm-deps-
```

GitHub Actions에는 CircleCI의 Docker 계층 캐싱(또는 DLC)에 해당하는 것이 없습니다.

## 작업 간에 데이터 유지

CircleCI와 GitHub Actions는 작업 간에 데이터를 유지하는 메커니즘을 제공합니다.

다음은 CircleCI 및 GitHub Actions 구성 구문의 예입니다.

### 작업 간에 데이터 유지를 위한 CircleCI 구문

```yaml
- persist_to_workspace:
    root: workspace
    paths:
      - math-homework.txt

...

- attach_workspace:
    at: /tmp/workspace
```

### 작업 간에 데이터를 유지하기 위한 GitHub Actions 구문

```yaml
- name: Upload math result for job 1
  uses: actions/upload-artifact@v4
  with:
    name: homework
    path: math-homework.txt

...

- name: Download math result for job 1
  uses: actions/download-artifact@v5
  with:
    name: homework
```

자세한 내용은 [워크플로 아티팩트와 데이터 저장 및 공유](/ko/actions/using-workflows/storing-workflow-data-as-artifacts)을(를) 참조하세요.

## 데이터베이스 및 서비스 컨테이너 사용

두 시스템 모두 데이터베이스, 캐싱 또는 기타 종속성에 대한 추가 컨테이너를 포함할 수 있습니다.

CircleCI에서 \_config.yaml\_에 나열된 첫 번째 이미지는 명령을 실행하는 데 사용되는 기본 이미지입니다. GitHub Actions는 명시적 섹션을 사용합니다. 즉, `container`를 기본 컨테이너에 사용하고 추가 컨테이너를 `services`에 나열합니다.

다음은 CircleCI 및 GitHub Actions 구성 구문의 예입니다.

### 데이터베이스 및 서비스 컨테이너 사용을 위한 CircleCI 구문

```yaml
---
version: 2.1

jobs:

  ruby-26:
    docker:
      - image: circleci/ruby:2.6.3-node-browsers-legacy
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby26
          POSTGRES_PASSWORD: ""

    working_directory: ~/administrate

    steps:
      - checkout

      # Bundle install dependencies
      - run: bundle install --path vendor/bundle

      # Wait for DB
      - run: dockerize -wait tcp://localhost:5432 -timeout 1m

      # Setup the environment
      - run: cp .sample.env .env

      # Setup the database
      - run: bundle exec rake db:setup

      # Run the tests
      - run: bundle exec rake

workflows:
  version: 2
  build:
    jobs:
      - ruby-26
...

- attach_workspace:
    at: /tmp/workspace
```

### 데이터베이스 및 서비스 컨테이너를 사용하기 위한 GitHub Actions 구문

<!-- markdownlint-disable search-replace -->

```yaml
name: Containers

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    container: circleci/ruby:2.6.3-node-browsers-legacy

    env:
      PGHOST: postgres
      PGUSER: administrate
      RAILS_ENV: test

    services:
      postgres:
        image: postgres:10.1-alpine
        env:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""
        ports:
          - 5432:5432
        # Add a health check
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      # This Docker file changes sets USER to circleci instead of using the default user, so we need to update file permissions for this image to work on GH Actions.
      # See https://docs.github.com/actions/using-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem

      - name: Setup file system permissions
        run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
      - uses: actions/checkout@v6
      - name: Install dependencies
        run: bundle install --path vendor/bundle
      - name: Setup environment configuration
        run: cp .sample.env .env
      - name: Setup database
        run: bundle exec rake db:setup
      - name: Run tests
        run: bundle exec rake
```

<!-- markdownlint-enable search-replace -->

자세한 내용은 [Docker 서비스 컨테이너와 통신](/ko/actions/using-containerized-services/about-service-containers)을(를) 참조하세요.

## 완성된 예시

다음은 실제 사례입니다. 왼쪽은 *thoughtbot/administrator* 리포지토리에 대한 실제 CircleCI [config.yml](https://github.com/thoughtbot/administrate)입니다. 오른쪽은 GitHub Actions의 동일한 항목입니다.

### CircleCI에 대한 전체 예시

```yaml
---
version: 2.1

commands:
  shared_steps:
    steps:
      - checkout

      # Restore Cached Dependencies
      - restore_cache:
          name: Restore bundle cache
          key: administrate-{{ checksum "Gemfile.lock" }}

      # Bundle install dependencies
      - run: bundle install --path vendor/bundle

      # Cache Dependencies
      - save_cache:
          name: Store bundle cache
          key: administrate-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Wait for DB
      - run: dockerize -wait tcp://localhost:5432 -timeout 1m

      # Setup the environment
      - run: cp .sample.env .env

      # Setup the database
      - run: bundle exec rake db:setup

      # Run the tests
      - run: bundle exec rake

default_job: &default_job
  working_directory: ~/administrate
  steps:
    - shared_steps
    # Run the tests against multiple versions of Rails
    - run: bundle exec appraisal install
    - run: bundle exec appraisal rake

jobs:
  ruby-25:
    <<: *default_job
    docker:
      - image: circleci/ruby:2.5.0-node-browsers
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""

  ruby-26:
    <<: *default_job
    docker:
      - image: circleci/ruby:2.6.3-node-browsers-legacy
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby26
          POSTGRES_PASSWORD: ""

workflows:
  version: 2
  multiple-rubies:
    jobs:
      - ruby-26
      - ruby-25
```

### GitHub Actions 대한 전체 예제

```yaml
# 이 워크플로는 GitHub에서 인증되지 않은 작업을 사용합니다.
# 작업은 타사에서 제공하며
# 별도의 서비스 약관, 개인정보처리방침, 지원 설명서에서 규정됩니다.
# 참조하세요.

# 커밋 SHA에 작업을 고정하는 것이 좋습니다.
# 최신 버전을 얻으려면 SHA를 업데이트해야 합니다.
# 태그 또는 분기를 참조할 수도 있지만 경고 없이 작업이 변경될 수 있습니다.

name: Containers

on: [push]

jobs:
  build:

    strategy:
      matrix:
        ruby: ['2.5', '2.6.3']

    runs-on: ubuntu-latest

    env:
      PGHOST: localhost
      PGUSER: administrate
      RAILS_ENV: test

    services:
      postgres:
        image: postgres:10.1-alpine
        env:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""
        ports:
          - 5432:5432
        # Add a health check
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      - uses: actions/checkout@v6
      - name: Setup Ruby
        uses: eregon/use-ruby-action@ec02537da5712d66d4d50a0f33b7eb52773b5ed1
        with:
          ruby-version: ${{ matrix.ruby }}
      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: vendor/bundle
          key: administrate-${{ matrix.image }}-${{ hashFiles('Gemfile.lock') }}
      - name: Install postgres headers
        run: |
          sudo apt-get update
          sudo apt-get install libpq-dev
      - name: Install dependencies
        run: bundle install --path vendor/bundle
      - name: Setup environment configuration
        run: cp .sample.env .env
      - name: Setup database
        run: bundle exec rake db:setup
      - name: Run tests
        run: bundle exec rake
      - name: Install appraisal
        run: bundle exec appraisal install
      - name: Run appraisal
        run: bundle exec appraisal rake
```