728x90

지난 글에 이어 CloudNet@의 CI/CD 스터디를 진행한 내용을 담고 있습니다.

GitHub Actions란?

GitHub Actions는 GitHub에서 제공하는 CI/CD(Continuous Integration/Continuous Deployment) 도구로,

코드를 빌드, 테스트, 배포하거나 자동화된 워크플로우를 실행할 수 있도록 지원합니다.

 

사전적 의미로 "리포지토리에서 소프트웨어 개발 워크플로우를 자동화, 사용자 지정 및 실행"할 수 있는 서비스입니다.

쉽게 말하자면 "이벤트를 받아 코드가 동작하는 컴퓨터"입니다.


GitHub Actions의 주요 구성 요소

 

 

 

  1. Event (이벤트)
    GitHub Actions를 트리거(실행)하는 조건으로, 주로 GitHub 저장소에서 발생하는 작업입니다.
    예:
    • push: 코드가 특정 브랜치로 푸시될 때
    • pull_request: 풀 리퀘스트가 생성, 열림, 닫힘 등 상태 변경 시
    • schedule: 정해진 시간에 실행 (크론 표현식 사용)
    • workflow_dispatch: 사용자가 수동으로 워크플로우를 실행
    예시:
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - develop
  schedule:
    - cron: "0 0 * * *"  # 매일 0시에 실행

 


  1. Runner (실행기)
    워크플로우를 실행하는 서버 또는 환경입니다.
    • GitHub-hosted Runner: GitHub에서 제공하는 가상 환경 (무료로 사용 가능).
      • Ubuntu, Windows, macOS 등 OS 환경 제공.
    • Self-hosted Runner: 사용자가 직접 구성한 머신에서 워크플로우 실행.
    러너의 역할:
    • 명령어와 스크립트를 실행.
    • 의존성 설치, 테스트, 빌드 작업 수행.

  1. Job (작업)
    워크플로우 내에서 실행되는 독립된 작업 단위입니다.
    여러 작업은 병렬로 실행되거나, 종속 관계를 설정하여 순차적으로 실행할 수 있습니다.

    예시:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
  test:
    runs-on: ubuntu-latest
    needs: build  # build가 끝난 후 실행
    steps:
      - name: Run tests
        run: npm test

  1. Step (스텝)
    각 Job 안에서 실행되는 작업의 세부 단계로, 실행하고자 하는 코드를 정의하는 부분입니다.
    • 명령어 실행: run 키워드 사용.
    • Action 호출: GitHub에서 제공하는 Action 재사용.
    예시:
steps:
  - name: Checkout code
    uses: actions/checkout@v3  # Action 호출
  - name: Install dependencies
    run: npm install  # 명령어 실행
  - name: Run tests
    run: npm test

 

 


  1. Action (액션)
    GitHub Actions의 재사용 가능한 작업 단위입니다.
    • 공식 GitHub Actions 또는 커뮤니티가 제공하는 액션을 사용하거나, 자신만의 커스텀 액션을 작성 가능.
    • 액션은 GitHub Marketplace에서 검색할 수 있습니다.
    예시:
steps:
  - name: Use Node.js
    uses: actions/setup-node@v3
    with:
      node-version: '16'  # Node.js 버전 설정

전체 구조 예시

다음은 GitHub Actions 워크플로우의 전체적인 예제입니다.

name: CI/CD Workflow

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: build  # build가 완료된 후 실행
    steps:
      - name: Deploy application
        run: npm run deploy

컴포넌트 요약

키워드 설명
Event 워크플로우를 실행시키는 트리거 이벤트
Runner 워크플로우가 실행되는 환경
Job 독립적인 작업 단위
Step Job 내에서 실행되는 구체적인 작업 단계
Action 재사용 가능한 단위 작업, GitHub 및 커뮤니티에서 제공

GitHub Actions는 CI/CD를 간단하게 설정하고 효율적으로 관리할 수 있게 해주는 강력한 도구입니다. 

 

직접 개발 후 실행하기

ec2를 직접 프로비저닝하고 코드 이식 후 동작을 확인해 봅니다.

ec2에서 하기 코드를 이식하여 간단한 HTTP 서버를 올립니다.

cat > server.py <<EOF
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from datetime import datetime

class RequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()
        now = datetime.now()
        response_string = now.strftime("The time is %-I:%M:%S %p, CloudNeta Study.\n")
        self.wfile.write(bytes(response_string, "utf-8")) 

def startServer():
    try:
        server = ThreadingHTTPServer(('', 80), RequestHandler)
        print("Listening on " + ":".join(map(str, server.server_address)))
        server.serve_forever()
    except KeyboardInterrupt:
        server.shutdown()

if __name__== "__main__":
    startServer()
EOF

 

터미널을 두대를 띄워놓고, python server를 동작시켜서 동작 내용을 확인합니다.

 

curl localhost를 동작시킬 경우, 위와 같이 GET method로 호출된 이력을 확인할 수 있습니다.

 

블로그 작성중에 여러 공격 시도가 있었네요.. 테스팅 리소스는 어디까지나 테스팅하시고 sg를 myIP로 한정해서 사용합시다..

103.173.227.187 - - [15/Dec/2024 18:33:12] code 501, message Unsupported method ('POST')
103.173.227.187 - - [15/Dec/2024 18:33:12] "POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1" 501 -
103.173.227.187 - - [15/Dec/2024 18:33:13] code 501, message Unsupported method ('POST')
103.173.227.187 - - [15/Dec/2024 18:33:13] "POST /cgi-bin/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/bin/sh HTTP/1.1" 501 -
103.173.227.187 - - [15/Dec/2024 18:33:13] code 501, message Unsupported method ('POST')
103.173.227.187 - - [15/Dec/2024 18:33:13] "POST /hello.world?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1" 501 -
103.173.227.187 - - [15/Dec/2024 18:33:14] "GET /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:15] "GET /vendor/phpunit/phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:16] "GET /vendor/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:17] "GET /vendor/phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:17] "GET /vendor/phpunit/phpunit/LICENSE/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:18] "GET /vendor/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:19] "GET /phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:20] "GET /phpunit/phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:21] "GET /phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:22] "GET /phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:22] "GET /lib/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:24] "GET /lib/phpunit/phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:24] "GET /lib/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:26] "GET /lib/phpunit/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:26] "GET /lib/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:27] "GET /laravel/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:28] "GET /www/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:29] "GET /ws/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:30] "GET /yii/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:31] "GET /zend/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:31] "GET /ws/ec/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:32] "GET /V2/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:33] "GET /tests/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:34] "GET /test/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:35] "GET /testing/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:36] "GET /api/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:37] "GET /demo/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:38] "GET /cms/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:39] "GET /crm/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:40] "GET /admin/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:41] "GET /backup/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:42] "GET /blog/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:43] "GET /workspace/drupal/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:44] "GET /panel/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:44] "GET /public/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:45] "GET /apps/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:46] "GET /app/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:47] "GET /index.php?s=/index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=Hello HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:48] "GET /public/index.php?s=/index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=Hello HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:49] "GET /index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?echo(md5("hi"));?>+/tmp/index1.php HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:50] "GET /index.php?lang=../../../../../../../../tmp/index1 HTTP/1.1" 200 -
103.173.227.187 - - [15/Dec/2024 18:33:50] "GET /containers/json HTTP/1.1" 200 -

 

Github access token을 설정합니다

하기와 같이 repo, workflow의 권한을 줍니다.

 

cicd-2w라는 리포지토리를 만들어줍니다.

 

그런 다음, 서버에서 다음과 같이 설정합니다.

password는 토큰을 입력합니다.

#
GITUSER=<>
GITUSER=jflip

git clone https://github.com/$GITUSER/cicd-2w.git
tree cicd-2w/
cp server.py cicd-2w/
cd cicd-2w/

#
git status
git add .
git commit -m "first commit"
git push origin main
Username for 'https://github.com': <>
Password for 'https://jflip@github.com': <>

 

서버 실행

#
nohup sudo python3 server.py > server.log 2>&1 &
cat server.log
curl localhost
cat server.log

#
grep log .gitignore
*.log

#
git add .
git commit -m "add log file"
git status

 

수정 후 재실행합니다.

#
sed -i "s/CloudNeta/CICD/g" server.py

# 프로세스 종료
sudo ss -tnlp
sudo fuser -k -n tcp 80
sudo ss -tnlp

# 재실행
nohup sudo python3 server.py > server.log 2>&1 &
curl localhost

 

 

코드 푸시를 다시 해봅니다.

번거로운 과정이었는데 이런 내용을 자동화합니다.

#
git config --global user.name jflip
git config --global user.email jflip@gmail.com
git config --global credential.helper store

#
git add . && git commit -m "version update" && git push origin main
Username for 'https://github.com': <>
Password for 'https://jflip@github.com': <>

#
git push origin main

 

<<내용 추가중입니다.>>

 

728x90
반응형