GitHub Actions で service のコンテナにリポジトリのファイルをマウントしようとするとエラーになる #GitHub #Actions

概要

GitHub Actions では、ジョブのサービスとして MySQL や Redis が使える。

volumes ( jobs.<job_id>.services.<service_id>.volumes ) を指定することで、サービス間やステップ間でデータを共有できる。

ただソースコードは通常 actions/checkout を利用すると思うが、リポジトリで管理しているようなファイルパスをそのままマウントしようとエラーになる。

rm: cannot remove '/home/runner/work/your_repo/path/to/mysql/conf.d': Permission denied

たとえば下記のような Workflow である。

jobs:
  job-name:
    runs-on: ubuntu-latest
    services:  
      mysql:  
        image: mysql
        ports:  
          - 3306:3306  
        volumes:  
          - ${{github.workspace}}/path/to/mysql/conf.d:/etc/mysql/conf.d

steps:  
  - uses: actions/checkout@v3  

原因

Workflow のジョブはサービスが立ち上がった後に動くため、 actions/checkout はマウント後に動く。

そうするとチェックアウトするディレクトリにマウントするディレクトリが存在する(空ではない)とされて、 actions/checkout は一度対象ディレクトリの中を空にしようとするようだ。

その際、サービスを動かすユーザーと actions/checkout を動かすユーザー(権限)異なるため、エラーになってしまう。

解決策

リポジトリをチェックアウトするディレクトリと、マウントする場所を分ければ解決する。

  • jobs.<job_id>.defaults.run の working-directory を設定する
  • チェックアウト場所を working-directory にする
  • 対象ファイルを cp などで移動する
jobs:
  job-name:
    runs-on: ubuntu-latest
  defaults:
    run:  
      working-directory: my_target
    services:  
      mysql:  
        image: mysql
        ports:  
          - 3306:3306
        volumes:  
          - ${{github.workspace}}/path/to/mysql/conf.d:/etc/mysql/conf.d

steps:  
  - uses: actions/checkout@v3
    with:  
      path: my_target
  - run: |  
      cp -r path/to/mysql/conf.d ${{github.workspace}}/path/to/mysql/conf.d

補足

working-directory の default を指定しているのは、 step の追加・変更時にパスをできるだけ意識せずに済むようにするため。

別に workflow 単位でも指定できるし、 step の中で cd してもよい。

例では MySQL の設定ファイルをマウントしているが、反映するためには大抵再起動が必要になるので、実際には data ファイルとかになると思う(テストデータを step 間で使い回すとか?)。

その他参考

docs.github.com