Overview
Github Action 학습한 내용을 정리합니다.
참고는 Github Action 공식 문서와 CloudNet@ CI/CD 스터디를 참고하였습니다.
Github Action
Github Action 은 원격 레파지토리인 github가 제공하는 워크플로우 솔루션입니다.
사용자가 정의한 워크플로(Workflow)를 통해 CI/CD 등 애플리케이션 자동화 작업을 실행할 수 있습니다.
GitHub Actions는 서버리스(Serverless) 방식으로 동작하여, GitHub의 실행 환경(호스트된 실행 서버)이 사용자가 정의한 작업을 대신 실행합니다.
워크플로우 구성만 하면 별도의 실행 환경 구성없이 자동화할 수 있다는 점과 GIt 이벤트(PR, 푸쉬, Issue) 에 유유연합니다. 젠킨스가 다양한 확장 플러그인을 제공하여 더욱 유연하지만, 실행 서버 관리가 필요없고 깃허브에서 코드를 관리한다면 좋은 선택지가 될 것 같습니다.
Github Action 구성요소
- Event(이벤트): 워크플로를 시작하는 트리거 동작이나 조건입니다.
- Runner(실행기): Job을 실행하는 호스팅 또는 셀프 호스트 환경입니다. 리눅스, 윈도우 등의 실행 환경을 설정할 수 있습니다.
- Job(작업): 여러 Step으로 구성된 단위 작업입니다. 작업 간 병렬 실행 또는 의존성 설정(순차 실행)이 가능합니다.
- Step(단계): Job 내에서 실행되는 개별 작업 명령입니다. 스크립트 실행, Action 호출 등이 포함됩니다.
각 단계는 repo 내 .github/workflows 경로의 yaml 파일 형식으로 구성합니다.
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push] # Event
jobs: # Jobs
Explore-GitHub-Actions:
runs-on: ubuntu-latest # Runner
steps: # Step
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
실행 환경 구성 (빌드 - 배포)
아마존 EC2 서버를 생성하고, 깃허브 액션을 통해 서버의 애플리케이션 배포를 자동화하겠습니다.
실행 환경 : (AWS) Ubuntu 22.04 amd64 t3.small
# 서버 내 실행
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
sudo python3 server.py
# 새터미널 서버 동작 확인
curl localhost
sudo ss -tnlp
깃허브 Repo를 생성하여 위 서버 코드를 올리겠습니다.
깃허브 작업은 다음과 같이 작업이 필요합니다.
- 깃허브 개인 계정 접근 토큰 발급(계정 > Setting > Developer Settings> Personal Access tokens 발급)
- Private Repo 생성
- 깃허브 내 EC2 서버 접근 키 입력
- 깃허브 액션 워크플로우 파일 작성
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
git clone https://github.com/HanHoRang31/cicd-2w.git
Cloning into 'cicd-2w'...
Username for 'https://github.com':
Password for 'https://tmdgh663@gmail.com@github.com': <위 접근 토큰 입력>
cp server.py cicd-2w/
cd cicd-2w
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git status
git add .
git commit -m "first commit"
git push origin main
깃허브 접근 키는 깃허브 > Repo > Setting > secrets and variables > secrets 에서 입력합니다.
- EC2_PIP ( EC2 서버 Public IP)
- SSH_PRIVATE_KEY ( 서버 접근 키)
이어서, .github/workflows/deploy.yaml 를 생성하여 다음과 같이 코드를 구성합니다.
name: CICD1
on:
workflow_dispatch:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Configure the SSH Private Key Secret
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- name: Set Strict Host Key Checking
run: echo "StrictHostKeyChecking=no" > ~/.ssh/config
- name: Git Pull
run: |
export MY_HOST="${{ secrets.EC2_PIP }}"
ssh ubuntu@$MY_HOST << EOF
cd /home/ubuntu/cicd-2w || exit 1
git pull origin main || exit 1
EOF
- name: Run service
run: |
export MY_HOST="${{ secrets.EC2_PIP }}"
ssh ubuntu@$MY_HOST sudo fuser -k -n tcp 80 || true
ssh ubuntu@$MY_HOST "nohup sudo -E python3 /home/ubuntu/cicd-2w/server.py > /home/ubuntu/cicd-2w/server.log 2>&1 &"
- Event(이벤트): Main 브랜치 Push 시 잡을 실행합니다.
- Runner(실행기): ubuntu-lastest에서 실행합니다.
- Step(단계): Job 내에 시크릿 키 등록 작업, 깃허브 풀 작업, 서버 배포 작업이 순차적으로 동작합니다.
워크플로우 파일을 Repo에 업로드하면 자동으로 깃허브 액션이 활성화됩니다.
git add . && git commit -m "add workflow" && git push origin main
필자는 구성 서버에서 git 글로벌 정보를 입력하고 다시 푸쉬해주세요
git config --global user.name hanhorang
git config --global user.email hanhorang@gmail.com
git config --global credential.helper store
잘 동작합니다!
워크플로우 구성(빌드 - 테스트 - 배포)
위 구성한 배포 단계에 테스트 과정을 추가하고, 민감 정보를 Repo 공유 없이 Github Action에서 사용하도록 구성하겠습니다.
- GitHub Actions에서 코드 가져오기
- GitHub Actions에서 .gitignore 제외된 민감 파일 내용을 을 안전하게 가져와서 사용하기 ⇒ 매번 수동으로 가져오기 불편하다!
- scp로 대상 서버 ec2 에 py 파일 전송
- 대상 서버 ec2에 기존 서비스 중지하고 다시 실행
먼저 REPO 깃허브 액션에서 민감 정보를 새로 입력합니다.
워크플로우를 아래와 같이 수정합니다.
아래 코드에서 핵심은 uses 입니다. 깃허브 액션에서도 젠킨스 플러그인과 같이 사용자 편의성의 파이프라인을 구성 후 가져와서 사용할 수 있습니다.
예제에서는 SCP(appleboy/scp-action@v0.1.7) 와 민감정보 사용을 위한 SSH uses(appleboy/ssh-action@v1.2.0)를 사용하였습니다.
기타 플러그인은 깃허브 마켓플레이스에서 확인이 가능합니다.
name: CICD2
on:
workflow_dispatch:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository Checkout
uses: actions/checkout@v4
- name: copy file via ssh
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.EC2_PIP }}
username: ubuntu
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: server.py
target: /home/ubuntu
- name: executing remote ssh commands
uses: appleboy/ssh-action@v1.2.0
env:
AWS_KEYS: ${{ secrets.MYKEYS }}
with:
host: ${{ secrets.EC2_PIP }}
username: ubuntu
key: ${{ secrets.SSH_PRIVATE_KEY }}
envs: AWS_KEYS
script_stop: true
script: |
cd /home/ubuntu/cicd-2w
echo "$AWS_KEYS" > .env
sudo fuser -k -n tcp 80 || true
rm server.py
cp /home/ubuntu/server.py ./
nohup sudo -E python3 /home/ubuntu/cicd-2w/server.py > /home/ubuntu/cicd-2w/server.log 2>&1 &
echo "test" >> /home/ubuntu/text.txt
git add . && git commit -m "Deploy CICD2 Final" && git push origin main
워크플로우 구성(With Ansible)
Github Action에 Ansible을 연동하면 절차적 형태가 아닌 선언적 형태로 CI/CD 파이프라인을 관리할 수 있습니다. 실제 운영 환경시 가독성과 재사용성을 높이고, 깃허브 액션에서 테스트와 배포를 Ansible을 통해 관리하여 쉽게 자동화할 수 있습니다.
Ansible 추가 워크플로우는 다음과 같이 구성할 수 있습니다.
Steps(단계):
- GitHub 리포지토리에서 코드를 가져옴
- Python 3.8 설치 및 Ansible 설치
- SSH 키를 설정하여 원격 서버와의 연결 준비
- Ansible 인벤토리 및 설정 파일 생성
- ping 테스트를 통해 원격 서버와의 연결 확인
- (주석 처리된) 플레이북 실행으로 서버 배포 작업 수행
name: Run Ansible
on:
workflow_dispatch:
push:
branches:
- main
jobs:
run-playbooks:
runs-on: ubuntu-latest
steps:
- name: Github Repository Checkout
uses: actions/checkout@v4
- name: Setup Python 3
uses: actions/setup-python@v5
with:
python-version: "3.8"
- name: Upgrade Pip & Install Ansible
run: |
python -m pip install --upgrade pip
python -m pip install ansible
- name: Implement the Private SSH Key
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- name: Ansible Inventory File for Remote host
run: |
mkdir -p ./devops/ansible/
export INVENTORY_FILE=./devops/ansible/inventory.ini
echo "[my_host_group]" > $INVENTORY_FILE
echo "${{ secrets.EC2_PIP }}" >> $INVENTORY_FILE
- name: Ansible Default Configuration File
run: |
mkdir -p ./devops/ansible/
cat <<EOF > ./devops/ansible/ansible.cfg
[defaults]
ansible_python_interpreter = '/usr/bin/python3'
ansible_ssh_private_key_file = ~/.ssh/id_rsa
remote_user = ubuntu
inventory = ./inventory.ini
host_key_checking = False
EOF
- name: Ping Ansible Hosts
working-directory: ./devops/ansible/
run: |
ansible all -m ping
# - name: Run Ansible Playbooks
# working-directory: ./devops/ansible/
# run: |
# ansible-playbook install-nginx.yaml
# - name: Deploy Python via Ansible
# working-directory: ./devops/ansible/
# run: |
# ansible-playbook deploy-python.yaml
git add . && git commit -m "Deploy Ansible Test" && git push origin main
참고
GIthub Action DoC
CloudNet@ CICD 스터디
'Cloud Tech' 카테고리의 다른 글
Kubernetes CI & CD (ArgoCD, Jenkins) (2) | 2024.12.22 |
---|---|
도커 기반 애플리케이션 CI/CD 구성 (0) | 2024.12.08 |
DownTime Zero를 통한 EKS 운영 안정성 높이기 (1) | 2024.11.02 |
Cilium Service Mesh on EKS (1) | 2024.10.26 |
EKS VPC CNI 네트워크 최적화 설정과 Kubeflow에서의 istio 구성 (2) | 2024.10.20 |