안녕하세요 늑대양 입니다
이번에 CloudNet@ 에서 진행하는 CI/CD Study 에 참여하게 되어 관련 내용을 정리하여 게시합니다
CloudNet@ URL: https://gasidaseo.notion.site/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
스터디는 3주간 진행되며, 2주차 주제는 GitHub Actions CI/CD 입니다.
GitHub Actions
GitHub Actions 공식 문서 URL: https://docs.github.com/ko/actions
GitHub Actions Docs URL: https://docs.github.com/ko/actions/about-github-actions/understanding-github-actions
GitHub Actions CI/CD
- GitHub Actions는 GitHub에서 제공하는 자동화 워크플로우 도구로, 코드 저장소 내에서 발생하는 이벤트를 기반으로 다양한 작업을 실행할 수 있습니다.
- 특히 CI/CD(Continuous Integration/Continuous Deployment)를 구현하기에 최적화되어 있어 개발자의 생산성과 코드 품질을 향상시키는 데 큰 기여를 합니다.
GitHub Actions 란?
- GitHub Actions는 GitHub의 저장소와 밀접하게 통합된 자동화 플랫폼으로, 다양한 작업을 워크플로우(Workflow)로 정의할 수 있습니다.
- 워크플로우는 YAML 형식의 설정 파일로 작성되며, 이벤트 발생 시 자동으로 실행됩니다.
- 이를 통해 코드 테스트, 빌드, 배포까지의 모든 과정을 자동화할 수 있습니다.
GitHub Actions 특징
- 완전한 통합: GitHub 저장소와 직접 연동되어 별도의 설정 없이도 Git 이벤트(Push, Pull Request 등)를 트리거로 활용 가능
- 유연성: 원하는 작업을 자유롭게 정의하고, 외부 API와 통합하거나 커스텀 액션을 작성 가능
- 확장성: GitHub Marketplace에서 다양한 액션을 다운로드하여 손쉽게 활용 가능
- 무료 사용 가능: 퍼블릭 저장소에서는 무료로 사용할 수 있으며, 개인 저장소에도 제한된 무료 사용량 제공
GitHub Actions 구성 요소
- 워크플로우(Workflow):
- 워크플로우는 하나 이상의 작업(Job)으로 구성되며, 특정 이벤트가 발생했을 때 실행됩니다.
- 워크플로우는 .github/workflows 디렉터리에 YAML 파일로 저장됩니다.
- 이벤트(Event):
- 워크플로우 실행을 트리거하는 GitHub 이벤트입니다.
- 예를 들어, push, pull_request, issue_comment 등이 있습니다.
- 잡(Job):
- 워크플로우 내에서 실행되는 작업 단위입니다.
- 각 잡은 특정 환경(예: ubuntu-latest)에서 실행되며, 여러 잡을 병렬 또는 순차적으로 실행할 수 있습니다.
- 스텝(Step):
- 각 잡 내에서 실행되는 개별 작업 단계입니다.
- 스크립트를 실행하거나, GitHub Actions에서 제공하는 프리셋 액션을 사용할 수 있습니다.
- 러너(Runner):
- 워크플로우를 실행하는 서버입니다.
- GitHub에서 호스팅하는 러너를 사용할 수도 있고, 자체 호스팅 러너를 설정할 수도 있습니다.
실습 환경 배포
- AWS 환경의 EC2 배포를 위한 CloudFormation Stack 을 생성합니다.
- 생성 중, Stack name 과 KeyName 에 대한 수정이 필요합니다.
- Instance 스펙은 기본 t3.small 로 높이거나 낮춰서 테스트 가능합니다.
- yaml 파일은 아래와 같으며, 생성되는 리소스는 아래와 같습니다.
- VPC 리소스:
- VPC
- IGW
- Pub Subnet + Route Table
- EC2 리소스:
- EC2 Instance (Ubuntu 22.04 이미지를 사용하며, ssh 접속 시 ubuntu 사용자 사용)
- Security Group (실습을 위해, SSH & HTTP 에 대해 오픈되어 있습니다)
- VPC 리소스:
AWS CloudFormation 배포를 위한 yaml 파일
1. 직접 개발 후 실행
서버 - GitHub: 직접 개발 후, 서버 실행 → 코드 수정 후 재실행
1.1 AWS EC2 접속 후 작업
# ubuntu 사용자를 사용하여, ssh 접속
# 로컬 진행
ssh ubuntu@<EC2 PUBLIC IP> -i <사용자 KEY PAIR>
#
python3 -V
#
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
## 아래 확인 후
CTRL+C 로 실행 취소
# (신규터미널) 서버1 SSH 접속
curl localhost
sudo ss -tnlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 5 0.0.0.0:80 0.0.0.0:* users:(("python3",pid=3065,fd=3))
2. Git 작업
2.1 Private repository 생성
2.2 토큰 발급
2.3 EC2 서버에서 git 작업
#
GITUSER=<사용자 ID>
#
git clone https://github.com/$GITUSER/cicd-2w.git
# password 항목에는 발급받은 토큰값 입력
#
tree cicd-2w/
cp server.py cicd-2w/
cd cicd-2w/
#
git config --global user.name <사용자 ID>
git config --global user.email <사용자 Email>
git config --global credential.helper store
#
git status
git add .
git commit -m "first commit"
git push origin main
Username for 'https://github.com': <>
Password for 'https://<사용자 ID>@github.com': <>
# 테스트를 위한 서버 실행
#
nohup sudo python3 server.py > server.log 2>&1 &
cat server.log
curl localhost
cat server.log
# server.log 가 git status에 ignore 되는 이유
# 참고로 *.log 는 Python 의 Django 관련 항목에 위치
grep log .gitignore
*.log
# .gitignore 확인 용도
git add .
git commit -m "add log file"
git status
# 기존 server.py 내 파일 수정
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 add . && git commit -m "version update" && git push origin main
Username for 'https://github.com': <>
Password for 'https://<사용자 ID>@github.com': <>
#
git push origin main
2. GitHub Actions -1-
서버 - GitHub Actions - my PC
GitHub Actions 으로 CI/CD 자동화 작업 실행
2.1 Git - Secret
- 아래의 두 항목에 대해, Secret 을 등록합니다
- SSH_PRIVATE_KEY: EC2 접속에 사용하는 키 (보안 상 매우 매우 중요)
- EC2_PIP: EC2 의 퍼블릭 IP
2.2 로컬 환경에서 Git 코드 작업
#
git clone https://github.com/gasida/cicd-2w.git
cd cicd-2w
#
mkdir -p .github/workflows/
touch .github/workflows/deploy.yaml
sed -i -e "s/CICD/CICD 2w/g" server.py
# 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 &"
2.3 Git push
#
git add . && git commit -m "add workflow" && git push origin main
2.4 코드 수정 후 동작 확인
# server.py 수정
sed -i -e "s/CICD 2w/CICD1 End/g" server.py
# deploy.yaml 수정
name: CICD1 End
on:
workflow_dispatch:
push:
branches:
- main
jobs:
deployfinal:
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 &"
#
git add . && git commit -m "edit workflow" && git push origin main
# EC2 서버에서 확인
grep -i cicd server.py
sudo ps -ef |grep server.py
tail /home/ubuntu/cicd-2w/server.log
3. GitHub Actions -2-
서버 - GitHub Actions - my PC
GitHub Actions 에서 '코드 - 빌드 - 테스트' 후 대상 서버에 전달 및 실행
실습 목표:
- GitHub Actions에서 코드 가져오기
- GitHub Actions에서 .gitignore 제외된 민감 파일 내용을 을 안전하게 가져와서 사용하기 ⇒ 매번 수동으로 가져오기 불편하다!
- scp로 대상 서버 ec2 에 py 파일 전송
- 대상 서버 ec2에 기존 서비스 중지하고 다시 실행
3.1 GitHub Actions 파이썬 버전 확인
# deploy.yaml
name: CICD2
on:
workflow_dispatch:
push:
branches:
- main
jobs:
deployfinal:
runs-on: ubuntu-latest
steps:
- name: Test
run: |
python -V || true
python3 -V || true
which python || true
which python3 || true
env
#
git add . && git commit -m "echo env" && git push origin main
# 출력값 확인
Python 3.10.12
Python 3.10.12
/usr/bin/python
/usr/bin/python3
3.2 GitHub Actions 에서 .gitignore 에 포함된 파일 사용
# .gitignore 제외된 민감 파일 내용 사용
#
grep env .gitignore
#
cat > .env <<EOF
ACCESSKEY : 1234
SECRETKEY : 5678
EOF
#
git add .env
git status
rm -f .env
# MYKEYS Secret 생성
ACCESSKEY : asdf1234
SECRETKEY : qwer1234
3.3 GitHub Actions Marketplaces
Marketplace URL: https://github.com/marketplace
3.3.1 SSH for GitHub Actions
URL: https://github.com/appleboy/ssh-action
# deployment.yaml
name: CICD2
on:
workflow_dispatch:
push:
branches:
- main
jobs:
ssh-deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository Checkout
uses: actions/checkout@v4
- 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
#
git add . && git commit -m "ssh action test" && git push origin main
3.3.2 scp
GitHub Action that copy files and artifacts via SSH
scp-action GitHub URL: https://github.com/appleboy/scp-action
scp-action Marketplace URL: https://github.com/marketplace/actions/scp-files
# server.py 수정
response_string = now.strftime("The time is %-I:%M:%S %p, SCP Test\n")
# deploy.yaml
name: CICD2
on:
workflow_dispatch:
push:
branches:
- main
jobs:
scp-ssh-deploy:
runs-on: ubuntu-latest
steps:
- name: Github Repository Checkout
uses: actions/checkout@v4
- 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
- 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/cicd-2w
# 업데이트 파일 push
git add . && git commit -m "using scp ssh action" && git push origin main
# EC2 서버에서 확인 작업 진행
ls -al ~/cicd-2w/
cat ~/cicd-2w/server.py | grep SCP
3.4 최종 실습
github action 에서 코드 가져오고 변경된 py 파일을 전송 후 기존 서비스 중지 후 재기동
# server.py 수정
response_string = now.strftime("The time is %-I:%M:%S %p, CICD2 End\n")
# deploy.yaml 수정
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 push
git add . && git commit -m "Deploy CICD2 Final" && git push origin main
4. GitHub Actions with Ansible
# deploy.yaml
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
실습 후 자원 삭제
- AWS CloudFormation Stack 삭제
- GitHub Repository(cicd-2w) 삭제
이것으로 CloudNet@ CI/CD Study - 2주차 - GitHub Actions CI/CD 내용을 마무리 합니다.
긴 글읽어주셔서 감사합니다.
다음 시간에 뵙겠습니다
'k8s > CloudNet@' 카테고리의 다른 글
CI/CD Study - 1주차 - Jenkins CI/CD + Docker (0) | 2024.12.07 |
---|---|
[CloudNet@] AWS EKS Workshop Study - 5주차. (0) | 2023.05.28 |
[CloudNet@] AWS EKS Workshop Study - 4주차. (0) | 2023.05.21 |
[CloudNet@] AWS EKS Workshop Study - 3주차. (0) | 2023.05.14 |
[CloudNet@] AWS EKS Workshop Study - 2주차. (0) | 2023.05.07 |