ぱんだツールズぱんだツールズ

技術背景

GitHub Actions / CircleCI / GitLab CI 乗り換えガイド

約8分

「GitHubのメインリポジトリをGitHub Actionsに統一したい」「会社がCircleCIからGitLab CIに移行する」—— CI/CDツールを乗り換えるとき、最初の壁は設定ファイルの構文の違いです。jobsの書き方、stepsのネスト、環境変数の渡し方…… 似ているようで細かく違います。 この記事では3つのCIツールの構文対応表と、乗り換え時のつまずきポイントを整理します。

1. 3ツールの設定ファイルの基本構造

まずは、GitHub Actions・CircleCI・GitLab CIで「同じ概念がどう書かれるか」を対応表で俯瞰します。 構文は違っても、やりたいこと(概念)は3ツールでほぼ共通です。

概念GitHub ActionsCircleCIGitLab CI
設定ファイル.github/workflows/xxx.yml.circleci/config.yml.gitlab-ci.yml
ジョブ定義jobs.xxxjobs.xxxxxx:(トップレベル)
ステップ実行steps: - run:steps: - run:script:
トリガーon:workflows.xxx.jobs.xxx.filtersonly: / rules:
環境変数(グローバル)env:environment:variables:
環境変数(秘匿)secretscontextCI/CD Variables
キャッシュactions/cacherestore_cache / save_cachecache:
Docker使用container:docker:image:
並列ジョブstrategy.matrixparallelismparallel:
アーティファクト保存actions/upload-artifactstore_artifactsartifacts:

この対応表が頭に入っていれば、移行作業の大半は「左の概念を、移行先の列の構文に置き換える」だけになります。 各ツールの細かい構文を横断的に引きたいときは、ぱんだツールズのCI/CD設定比較ツールで対応構文をその場で検索できます。

2. 主な移行パターン(コード例付き)

GitHub Actions → CircleCI の書き換え例

どちらもjobsstepsを持つので構造は近いですが、 再利用アクションの呼び方とシークレットの渡し方が変わります。

  • チェックアウト:uses: actions/checkout@v4→ CircleCIの組み込みステップ - checkout
  • 並列展開:strategy.matrix→ テスト分割なら parallelism、 変数の組み合わせなら parameters + matrix
  • 秘匿情報:${{ secrets.TOKEN }}→ CircleCIの context を割り当てて$TOKEN として参照

GitHub Actions → GitLab CI の書き換え例

こちらは構造が一番大きく変わります。ジョブがトップレベルに移動し、stepsがscriptになるのがポイントです。

  • トリガー:on: push: branches: [main]rules: - if: $CI_COMMIT_BRANCH == "main"
  • ジョブとステップ:jobs.build.steps→ トップレベルの build: script:
  • 環境変数:env:variables:(参照は ${{ env.VAR }}$VAR

この変換でとくに注意したいのはインデントです。GitHub Actionsではjobs:配下にあったジョブが、 GitLab CIではトップレベルへ移るため、コピー後はインデントを1段ぶん浅くする必要があります。

3. よくあるつまずきポイント3選

(1) YAMLインデント地獄

GitLab CIはジョブがトップレベル、GitHub ActionsとCircleCIはjobs:配下という階層の違いがあります。 他ツールからコピーしたジョブをそのまま貼ると、インデントが1段ズレてパースエラーになりがちです。 YAMLはインデントが文法そのものなので、移行時はyamllintやエディタのYAML拡張で 構文を検証しながら進めるのが確実です。

(2) 環境変数の渡し方の違い

GitHub Actionsの${{ env.VAR }}と GitLab CIの$VARは記法が異なります。 GitHub Actionsはワークフロー式(${{ }})と シェル変数($VAR)が文脈によって使い分けられるという 二重ルールがあり、これを意識せず$VARに 一括置換すると、条件式やwith内の参照が壊れます。

(3) キャッシュキーの設計

ツールによってキャッシュの永続化の仕組みが違うため、移行後にキャッシュが効かないことがあります。 GitHub Actionsはロックファイルのハッシュをキーに含めるのが定番、CircleCIはrestore_cache/save_cacheの ペアで明示管理、GitLab CIはcache:のkeyとpathsで宣言します。 キー生成ルールが違うと旧キャッシュが復元されず、ビルド時間が逆に伸びることもあるため、 移行直後はキャッシュヒット率を必ずチェックしてください。

4. 移行手順

実際の乗り換えは、次の4ステップで進めると漏れがありません。

  1. 現行の設定ファイルを分析する — ジョブ・ステップ・環境変数・シークレット・キャッシュ・並列設定を洗い出し、移行対象をリスト化する
  2. 対応表で構文を読み替える — 本記事の対応表を見ながら、各概念を移行先の構文へ1対1で変換する(GitLab CIならジョブをトップレベルへ・インデント1段浅く)
  3. シークレット・環境変数を新環境に登録する — 設定ファイルには書けない秘匿情報を、移行先の管理画面(Secrets / Context / CI/CD Variables)に再登録する
  4. ブランチを使って動作確認する — 検証用ブランチで新設定を走らせ、ジョブの成否・キャッシュ・並列実行を確認してからデフォルトブランチへマージする

構文の読み替えで詰まったら、CI/CD設定比較ツールで「この概念は移行先でどう書くか」をその場で確認できます。すべてブラウザ内で完結するため、 社内リポジトリの設定でも安心して参照できます。

5. まとめ

  • 3ツールの概念は同じ、構文だけが違う。対応表で読み替えれば移行作業の大半は機械的に進む
  • GitLab CIはジョブがトップレベルでインデントが浅い・stepsがscriptになる、という構造差が最大のポイント
  • 環境変数の記法(${{ env.VAR }} vs $VAR)の違いに注意
  • シークレットは設定ファイルとは別に、移行先の管理画面で再登録が必須
  • キャッシュキーの設計差で移行後にキャッシュが効かなくなることがあるため、ヒット率を確認する
  • 本番にいきなり反映せず、検証用ブランチで動作確認してからマージする

よくある質問

GitHub Actions・CircleCI・GitLab CIで設定ファイルの置き場所はどう違いますか?

GitHub Actionsはリポジトリ直下の.github/workflows/配下に任意名の.ymlファイルを複数置けます。CircleCIは.circleci/config.ymlという決まったパスの1ファイルに集約します。GitLab CIはリポジトリ直下の.gitlab-ci.ymlが基準ですが、include機能で他ファイルを取り込めます。「複数ファイルに分割できるか」「決め打ちのパスか」という違いがまず最初のつまずきポイントになります。

jobsの書き方の違いで一番つまずくのはどこですか?

GitHub ActionsとCircleCIはどちらもjobs:というキーの下にジョブを並べますが、GitLab CIはジョブをトップレベルに直接書きます。たとえばbuildというジョブは、GitHub/CircleCIではjobs.build、GitLab CIでは単にbuild:と書きます。GitLab CIではトップレベルのキーがジョブ名になるため、stages・variables・defaultなどの予約語と名前が衝突しないよう注意が必要です。

stepsとscriptの違いは何ですか?

GitHub ActionsとCircleCIはジョブ内にsteps:という配列を持ち、各ステップでrun(コマンド実行)やuses/checkout(再利用アクション)を並べます。GitLab CIにはstepsという概念がなく、ジョブ内のscript:にシェルコマンドを配列で書きます。前処理はbefore_script、後処理はafter_scriptに分けます。「ステップの配列」か「スクリプトのリスト」かという構造の違いを押さえると移行がスムーズです。

環境変数の渡し方はどう書き換えればいいですか?

グローバルな環境変数はGitHub Actionsではenv:、CircleCIではenvironment:、GitLab CIではvariables:で定義します。参照側も異なり、GitHub Actionsはワークフロー式の${{ env.VAR }}、CircleCIとGitLab CIはシェル変数の$VARで参照します。GitHub Actionsはrun内のシェルでは$VARも使えますが、条件式やwith内では${{ }}が必須という二重ルールがあるため、ここが移行時の頻出ミスです。

秘匿情報(シークレット)の扱いはどう違いますか?

GitHub Actionsはリポジトリ/組織のSecretsに登録し${{ secrets.TOKEN }}で参照します。CircleCIはプロジェクト環境変数またはContext(複数プロジェクトで共有する秘匿情報グループ)を使います。GitLab CIはCI/CD Variablesでprotected/maskedフラグを付けて管理します。秘匿値は設定ファイルには書けないため、移行時はファイル書き換えとは別に、新環境の管理画面でシークレットを再登録する作業が必ず発生します。

キャッシュの設定が移行後に効かなくなるのはなぜですか?

キャッシュの仕組みがツールごとに違うためです。GitHub Actionsはactions/cacheアクションでkeyとpathを指定、CircleCIはrestore_cache/save_cacheのペアで明示的に復元・保存、GitLab CIはcache:キーでkeyとpathsを宣言します。とくにキャッシュキーの生成ルール(ロックファイルのハッシュを使うか等)が異なるため、単純に書き換えるとキーが一致せずキャッシュミスが多発します。移行後はキャッシュヒット率を必ず確認してください。

並列実行(マトリクスビルド)はどう対応付けますか?

GitHub Actionsはstrategy.matrixで変数の組み合わせごとにジョブを展開します。CircleCIはparallelismで同一ジョブを指定数に分割(主にテスト分割)し、マトリクス的な展開はparametersとmatrixを組み合わせます。GitLab CIはparallel(数値指定で分割)またはparallel:matrixで実現します。「変数の直積で展開」と「単純な並列分割」は意味が違うため、元の意図を確認してから読み替えるのが安全です。

トリガー条件(特定ブランチでのみ実行など)はどう書き換えますか?

GitHub Actionsはon:でpush/pull_requestなどのイベントとbranchesフィルタを指定します。CircleCIはworkflowsの中でジョブにfiltersを付けてブランチを絞ります。GitLab CIは古いonly:/except:、または推奨されるrules:でif条件($CI_COMMIT_BRANCH == "main"など)を書きます。GitLab CIではrules:が現在の推奨で、only/exceptは非推奨扱いになりつつある点に注意してください。

Dockerイメージの指定方法はどう違いますか?

GitHub Actionsはジョブにcontainer:を指定するか、runs-onでランナーOSを選びます。CircleCIはジョブ直下のdocker:に実行イメージを列挙します(先頭がプライマリコンテナ)。GitLab CIはimage:でジョブの実行イメージを指定し、追加サービスはservices:で起動します。DBなどの付随コンテナの指定方法(CircleCIはdocker配列の2番目以降、GitLab CIはservices)が異なる点が見落としがちです。

YAMLのインデントエラーが移行後に頻発するのはなぜですか?

ジョブの階層構造がツールごとに違うためです。GitHub ActionsとCircleCIはjobs:配下にジョブをネストしますが、GitLab CIはジョブがトップレベルに置かれます。そのため機械的にコピーするとインデントが1段ズレてパースエラーになりがちです。移行時はYAMLリンター(yamllintなど)で構文を検証しながら進めると安全です。

設定ファイルの内容はサーバーに送信されますか?

ぱんだツールズのCI/CD設定比較ツールは、すべての処理をブラウザ内で完結させます。入力した設定内容やコードがサーバーに送信されることはないため、社内リポジトリの設定ファイルを扱う場合でも安心して比較・参照できます。

この記事で紹介したツール