본문 바로가기
AWS & CICD

[DevOps] Git Actions Self-hosted Runner로 배포 자동화 파이프라인 구축

by rla124 2025. 4. 9.

문제 상황: SSH 타임아웃

캡스톤 플젝에 대한 게시글!  일반적으로 AWS 클라우드 서버를 사용하는데 컴공과 캡스톤 수업의 경우 대학 측에서 교내 서버를 대여해 줄 수 있다고 했고, 우리 팀은 학교 NAT 환경에서 확인한 공인 IP로 승인을 받아 해당 IP로만 학교 서버에 접근이 가능한 상황이었다.
이 상황에서 일반적인 AWS 기준의 배포 스크립트를 작성할 경우 나타났던 문제점과 해결 방안에 대해 기록하고자 한다.
 
 
ssh 연결을 통한 접속을 해야했기에 교내 캡스톤 서버에서 ssh-keygen을 통해서 개인키와 공개키를 이미 만들어 둔 상황이었다.

개인키공개키
git secret로 관리개인 settings ssh key로 관리
actions runner가 서버 ssh 접속할 수 있도록 함github이 서버로부터 오는 요청(git clone etc.)을 허용하게 하기 위함
-----BEGIN OPENSSH PRIVATE KEY----- ..로 시작, 끝을 이루는 수미상관 형식ssh-rsa로 시작

 
(이 부분에서도 많은 시행착오를 겪었는데 개인키와 공개키 형식을 구별해서 잘 할당해야 했다.. if not, value type invalid error가 발생한다)
 
그러나 배포 스크립트 상 개인키를 이용해 서버에 ssh 연결을 시도하는 단계(ssh -i)에서 계속 timeout 문제가 발생했다. 

name: Deploy to Server

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Setup SSH Key
        run: |
          echo "${{ secrets.DEPLOY_SSH_KEY }}" > deploy_key
          chmod 600 deploy_key

      - name: Clone Project to MobaXTerm Server
        run: |
          ssh -i deploy_key -o StrictHostKeyChecking=no team12@${{ secrets.SERVER_IP }} << 'EOF'
            echo "Preparing default directory"
            mkdir -p /data1/team12
            cd /data1/team12

            echo "Cleaning up old git repo (if exists)"
            rm -rf .git 

            echo "Cloning from GitHub"
            git clone git@github.com:NoSleep-Drive/ai-model.git .

            echo "Deployment complete"
          EOF

 
 

해결 방법: Self-hosted Runner 이용

Github Actions는 공용 네트워크에서 실행이 된다. 우리 팀은 학교 NAT 공인 IP로만 접근할 수 있었기 때문에 단순 git actions로는 사설망 서버에 접근할 수 없었던 것이다. 그렇다면 필요한 것은 역발상이었다.
git actions이 서버에 직접 접속을 하는 것이 아니라! 서버가 직접 명령 요청이 들어오면 그 서버 내부에서 명령을 수행하면 되지 않을까?
이 방법을 가능하게 하는 것이 Self-hosted Runner 였다.
 
깃허브 레포 별로 actions>runner 항목에서 위 방법을 이용할 수 있는 사전 작업 명령어가 소개되어있다. 서버에 설치가 필요한 github actions runner를 다운 받는 코드를 순차적으로 서버 cmd에서 실행시키면 된다.
 
cat /etc/os-release를 통해 운영체제를 확인해보니 Ubuntu 였고, uname -m을 통해 cpu 아키텍쳐를 확인해보니 x86_64였다. 깃 레포 runner 설치 명령어 옵션에서는 MacOS, Linux, Window를 지원하고 있고 x64, arm을 선택하도록 되어있어서 서버 환경에 맞는 항목을 선택해 나오는 명령어를 차례로 실행해주면 된다. 

mkdir actions-runner && cd actions-runner

curl -o actions-runner-linux-x64-2.312.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.312.0/actions-runner-linux-x64-2.312.0.tar.gz

tar xzf actions-runner-linux-x64-2.312.0.tar.gz

./config.sh --url https://github.com/NoSleep-Drive/ai-model --token MY_ALLOCATED_TOKEN_HERE

 
 
그리고 runner 기반으로 수정한 배포 스크립트는 아래와 같다.

name: Deploy via Internal Runner

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: self-hosted
    environment: deploy

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup SSH Key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan github.com >> ~/.ssh/known_hosts

      - name: Configure Git Identity
        run: |
          git config --global user.name "GitHub Actions"
          git config --global user.email "actions@github.com"

      - name: Clone or Pull Repository
        run: |
          set -e

          cd /data1/team12

          if [ -d "ai-model/.git" ]; then
            echo "Repository exists -> pulling latest changes..."
            cd ai-model
            GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git pull origin main
          else
            echo "Repository not found or not a git repo -> cloning from scratch"
            rm -rf ai-model 
            GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git clone git@github.com:NoSleep-Drive/ai-model.git
          fi

          echo "Model Deployment Ready"

 
 
이렇게 되면 main에 push가 되었을 때 캡스톤 서버로 MobaXTerm으로 접속하고,
설치된 runners 경로(default 경로/actions-runner/actions-runner)로 이동한 뒤,
./run.sh를 실행해주면 서버 내에서 git actions의 연결 요청을 승인하여 자체적으로 스크립트를 실행하게 된다.
 
이때 주의하면 좋은 점이, 이미 runners를 설치할 때 내장된 run.sh를 실행하면 ssh 연결 여부를 묻는 질문이 나오는데 매번 yes라고 입력해야 한다는 점이다. 아래 설정을 통해 이를 자동화할 수 있었다.

GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no"

깃이 내부적으로 ssh를 쓸 때, 호스트 키를 체크하지 않고 자동으로 yes로 처리하는 설정이다. 
 

기타 트러블슈팅: Git Identity

위 최종 배포 스크립트가 도출 되기 전에 있었던 작은 문제와 해결방안도 함께 소개하고자 한다. 
이미 서버로 배포가 되었고 코드 파일을 수정하여 다시 푸시했을 때 main branch로 배포 트리거가 설정되어있어서 deploy가 시작된다.
하지만 아래와 같은 오류에 직면했다.

Run cd /data1/team12
From github.com:NoSleep-Drive/ai-model
 * branch            main       -> FETCH_HEAD

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'team12@devbox.(none)')
Error: Process completed with exit code 128.

 
이 부분은 레포지토리 디렉토리가 이미 존재해서 pull을 했지만 리모트와 로컬의 커밋 상태가 다르므로 머지 커밋 과정에서 생긴 에러이다. Git은 이때 사용자 정보가 필요하므로 global로 git config를 해주는 부분을 별도의 name step으로 추가하는 계기가 되었다. 
 
 
오호~ 이런 배포 방식도 가능하구나 하며 배울 수 있었다. Today What I Learn
추후 모델 배포에 대해서 작성하려 한다.