Github action self-hosted runner 사용시 주의사항 (feat. use container)


한줄 정리

  • github-action self-hosted runner에서 jobs.<job_id>.container를 사용 할 경우, checkout이나 build output들이 root 권한으로 생성되어 jobs.<job_id>.container를 사용하지 않은 job이 실패 할 수 있습니다.

권한 문제 발생

이 github action은 cleanup에서 삭제 rm -rf dist; 명령은 파일 접근 권한이 없어서 실패하게 됩니다

name: publish

on:
  push:
    tags:
      - "*"

jobs:
  build:
    runs-on: [self-hosted, Linux]
    container:
      image: "node:22"

    steps:
      - name: checkout code
        uses: actions/checkout@v4

      - name: build observable
        run: |
          make publish out-dir=./dist;          

  cleanup:
    runs-on: [self-hosted, Linux]
    needs: build
    steps:
      - name: remove build output
        run: |
          rm -rf dist;          

왜?

  • 이유 아래 2가지가 원인 입니다.
    1. docker container 내에서 실행 되는 명령은 기본적으로 root 권한(userID=0)으로 실행 됩니다.
    2. github action에서 container를 사용하게 되면 workspace 및 temp 디렉토리는 container 없이 실행할때와 동일한 경로의 디렉토리가 container에 mount 되는 형태로 작동 합니다.
      • github action의 로그 중 Initialize containers의 로그를 보면 알 수 있습니다.
/usr/bin/docker create --name 34ab908b78a34c2a9ff8116de7bb9d7e_node22_a144dc \
    --label b3cf3f --workdir /__w/<repository-name>/<repository-name> \
    --network github_network_086481fb0d294dcc870557186e416af1 \
    -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true \
    -v "/var/run/docker.sock":"/var/run/docker.sock" \
    -v "/home/ruinnel/actions-runner/_work":"/__w" \
    -v "/home/ruinnel/actions-runner/externals":"/__e":ro \
    -v "/home/ruinnel/actions-runner/_work/_temp":"/__w/_temp" \
    -v "/home/ruinnel/actions-runner/_work/_actions":"/__w/_actions" \
    -v "/home/ruinnel/actions-runner/_work/_tool":"/__w/_tool" \
    -v "/home/ruinnel/actions-runner/_work/_temp/_github_home":"/github/home" \
    -v "/home/ruinnel/actions-runner/_work/_temp/_github_workflow":"/github/workflow" \
    --entrypoint "tail" node:22 "-f" "/dev/null"

회피하는 방법

  • action-runner를 root 권한으로 실행하면 해결 될 수 있습니다. 하지만 보안상 추천하지 않습니다.
  • jobs.<job_id>.container.options--user <UID> 을 추가 합니다.
    • UID는 linux라면 id -u으로 획득 가능합니다.
    • UID는 서버에 첫 등록된 사용자라면 1000입니다. 하지만 환경에 따라 달라질 수 있습니다.
    • 그러므로, container 밖에서 동작하는 job에서 id -u 명령으로 획득 후 output으로 다음 job에 전달 할 수 있습니다.
name: publish

on:
  push:
    tags:
      - "*"

jobs:
  detect-user:
    runs-on: [self-hosted, Linux]
    outputs:
      UID: ${{ steps.get-uid.outputs.UID }}
    steps:
      - name: get action-runner`s UID
        id: get-uid
        run: |
          echo "UID=$(id -u)" >> $GITHUB_OUTPUT          

  build:
    runs-on: [self-hosted, Linux]
    needs: [detect-user]
    container:
      image: "node:22"
      options: --user ${{ needs.detect-user.outputs.UID }}

    steps:
      - name: checkout code
        uses: actions/checkout@v4

      - name: build observable
        run: |
          make publish out-dir=./dist;          

  cleanup:
    runs-on: [self-hosted, Linux]
    needs: build
    steps:
      - name: remove build output
        run: |
          rm -rf dist;          

참고 문서

comments powered by Disqus