Local
Dev
Staging
Production
개발 환경을 나누는 이유?
Dev, Staging, Production이 같게 되면 소스 코드를 저장하는 순간 바로 반영이 된다. 개발할때 생길 수 있는 여러 치명적인 문제를 최소화 하기 위한 방법이다.
현업 Git Flow
main과 staging, dev 브랜치가 존재하며 각 브랜치는 각각 알맞은 서버와 매핑되어 있는 환경이다. 즉 dev에 존재하는 코드는 dev서버에 존재하고 테스트를 해야 한다.
반복적인 테스트를 위와 같이 매번 하는것은 굉장히 번거로운 일이다.
이런 문제점을 보완하고 나온 개념이 Continuous Integration(CI), 지속적 통합이다. CI는 새롭게 작성한 코드 변경을 자동으로 Build하고 Test 진행 후 Test Case에 통과했는지 확인하게 된다.
Continuous Deploy/Delivery(CD), 지속적 배포는 작성한 코드가 항상 신뢰 가능한 상태가 되면(CI 통과) 자동으로 배포될 수 있도록 하는 과정이다. 즉 CI진행 후 CD를 진행하는 프로세스이며 dev/staging/main 브랜치에 Merge가 될 경우 자동으로 알맞은 서버로 배포하게 된다.
CI/CD를 활용할 수 있는 도구로는 Jenkins, circleci, Travis CI, AWS CodeDeploy, GCP Cloud Build, Github Action 등이 존재한다.
Github에서 출시한 기능으로, 소프트웨어 Workflow 자동화를 도와주는 도구
1. Test code
2. 배포
3. 파이썬, 쉘 스크립트 실행
4. Gtihub Tag, Release 자동으로 설정
5. etc
그 외 다양한 Workflow를 만들 수 있다.
Action Marketplace에 존재하는 action을 사용할 수 있다.
github Action pricing
Public Repo는 무료지만 Private Repo는 유료로 이용해야 한다.
github Action 제약조건
하나의 Repo당 workflow는 최대 20개까지 등록할 수 있으며 workflow에 존재하는 Job(실행)은 최대 6시간 실행할 수 있다. 그 시간이 초과되면 자동으로 중지되며 동시에 실행할 수 있는 Job의 제한도 존재한다.
코드 작업
코드 작업 후, Github Action으로 무엇을 할 것인가 생각
사용할 Workflow정의 (기존의 Workflow중 사용할게 없으면 쉘스크립트 자동화도 고려해볼 수 있다.)
Workflow 정의 후 정상 작동하는지 확인
핵심개념 : Workflow, Event, Job, Step, Action, Runner
1. Workflow
Workflow는 최상위 개념으로 무엇을 자동화할지 이름으로 구성하고 그 아래에 여러개의 Job으로 구성된다. 또한 Event로 Trigger(실행)되는 방식을 거친다.
Workflow 파일은 YAML으로 작성되고, Github Repository의 .github/workflows폴더에 저장한다.
2. Event
위의 사진을 보면 on에 해당하는 부분이 Event이며 push가 될때마다 실행하겠다는 의미이다. 이 부분에 특정 브랜치에 push, Pull Request, merge나 특정 시간대에 반복(Cron)등을 지정할 수 있다.
3. Jobs
Runner라는 서버에서 실행되는 Steps의 조합이다.
일련의 작업이라고 생각할 수 있으며 여러 Job으로 구성되어 있는 경우 병렬, 순차적 실행을 설정할 수 있으며 다른 Job에 의존 관계를 가질 수 있다.
4. Steps
Step은 Job에서 실행되는 개별 작업으로 Action을 실행하거나 쉘 커맨드는 실행하는 작업이 실행된다. 하나의 Job에서는 데이터 공유가 가능하다.
5. Actions
Workflow의 제일 작은 단위로 Job을 생성하기 위해 여러 Step을 묶는 개념이다. 재사용이 가능한 Component로 개인적으로 Action을 만들 수 있고 Marketplace의 Action을 사용할 수 있다. Action을 YAML파일에서 uses 부분에서 확인할 수 있다.
6. Runner
github Action도 일종의 서버에서 실행되는 개념으로 Workflow가 실행될 서버이다. github-hosted Runner는 vCPU 2, Memory 7GB, Storage 14GB의 성능을 가지고 있으며 직접 서버를 호스팅해서 사용하는 self-hosted Runner 방법을 사용할 수 있다.
새로운 repository를 생성 후 hello-wolrd.py
파일을 생성하고 print문을 작성 후 저장한다.
상단의 Actions탭에서 Python application의 configure를 클릭하면 YAML파일이 생성된다.
runs-on은 실행 환경에 대한 정보이다.
uses는 사용할 github Action을 명시하고 name은 step의 이름을 명시한다. uses가 없는 경우 run으로 쉘 커맨드를 실행하는 의미이다.
진행 순서
Compute Engine 실행
SSH 키 생성 및 Github Secrets 설정
터미널에서 최초로 서비스 실행
Github Action을 통한 배포 자동화
지난 시간에 배웠던 GCP에서 Compute Engine의 VM 인스턴스를 생성한다.
실습환경은 Region은 서울 머신 유형은 e2-standard-2(vCPU 2개, 8GB 메모리)로 진행한다. 실습 후 인스턴스를 바로 삭제하기 때문에 무료 크레딧으로 사용할 수 있으며 비용이슈는 발생하지 않는다.
또한 부팅 디스크 부분에서 운영체제를 설정할 수 있으며 실습 환경에서는 Ubuntu 20.04 LTS, 30GB로 설정한다.
인스턴스가 생성이 완료되면 SSH를 클릭하여 브라우저 창에서 열기를 클릭한다.
CLI환경이 로드되면 SSH Key를 생성해야 한다.
cd ~/.ssh/
ssh-keygen -t rsa -b 4096 -C "my email"
passphrase
는 엔터를 쳐도 기본설정으로 생성한다.
id_res.pub
이 생성되었다면 cat id_rsa.pub >> authorized_keys
로 파일을 생성한다.
authorized_keys
에 퍼블릭 키가 등록되면 외부에서 접근이 가능하지만 GCP는 주기적으로 authorized_keys 파일을 삭제해서 외부에서 키파일 등록하는 과정이 필요하다.
따라서 cat id_rsa.pub
을 사용해 내용을 복사한다.
GCP Console로 이동한 후 좌측 메뉴에서 메타데이터를 클릭 후 SSH 키를 추가할 수 있다.
위의 과정을 정상적으로 완료했다면 실습을 위해 zzsza Repo의 내용을 Fork해온다.
Fork를 해왔다면 해당 Repository에서 Settings - Secrets - Actions로 이동하여 New repository secret을 클릭한다. secret이란 일종의 변수같이 사용할 수 있는것으로 암호처럼 외부에 노출되면 안되는 값을 이 기능으로 생성하게 된다.
해당 secret에는 HOST라는 이름으로 VM인스턴스의 외부 아이피주소를 복사하여 저장한다.
다음 secret을 생성후 USERNAME으로 VM인스턴스의 username을 추가한다.
마지막으로 Private SSH를 등록해야하는데 VM인스턴스 환경에서 id_rsa
파일을 복사하여 SSH_KEY라는 이름으로 등록해준다. private key값을 길기 때문에 vi를 이용해서 복사할 수 있다.
이렇게 등록된 secrets들은 Github Action에서 Secret을 활용할 수 있다.
${{secrets.HOST}}
와 같이 secrets에 저장된 HOST의 값을 가져올 수 있다.
VM인스턴스 서버로 접속한 후 git config --global credential.helper store
를 사용해 Github Action에서 추가 인증없이 사용하고 Fork한 저장소를 clone해준다.
clone이 완료되면 필요한 프로그램을 설치해준다.
sudo apt-get update
sudo apt-get install python3.8-venv -y
설치가 완료되면 clone한 repository의 part2 --> 04-cicd로 이동한 후 아래의 명령어를 실행해준다.
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
설치 중 error는 기다리면 진행이 된다.
설치가 완료되면 nohup streamlit run app.py --server.runOnSave true &
를 실행한다.
runOnSave
: 파일이 변경될 경우 자동으로 다시 실행하는 기능이다.
cat nohup.out
로 외부 URL정보를 확인할 수 있다.
해당 URL로 접속하면 병화벽 이슈로 인해 접속이 불가능 한데 GCP console에서 방화벽 규칙 설정을 클릭한다.
해당 메뉴에서 방화벽 규칙 만들기를 클릭하여 이름과 대상을 지정된 대상 태그로 한 후 태그 이름을 설정한다. 이 옵션은 해당 태그가 compute engine에 쓰이면 이 규칙을 적용하겠다는 의미이다.
생성된 방화벽을 Compute Engine에 적용하기 위에 Compute Engine페이지에 인스턴스이름을 클릭한다. 상단의 수정버튼을 누른 후 네트워크 태깅 섹션에서 태그 이름을 추가한다. 여러개를 추가할 경우 쉼표로 구분한다.
태그가 완료되었다면 다시 외부 url로 접속하면 접속이 되는것을 확인할 수 있다.
여기까지가 streamlit을 Cloud환경에 띄운것이라 말할 수 있다. 다만 CI/CD와 같이 배포 자동화를 다루진 않았으며 다음 내용에서 다룰 예정이다.
배포 자동화 실습을 위해 Fork한 Repository로 이동 후 Actions를 클릭 후 understand를 클릭한다.
해당 Repository에는 이미 Actions(YAML파일)이 존재하고 Boostcamp-AI-Tech-Product-Serving/.github/workflow/deploy_ssh.yml
로 이동해서 파일을 확인한다.
위에서 부터 살펴보면서 어떻게 구성되어 있는지 살펴본다.
해당 Action의 이름은 CICD-SSH로 이루어져 있고 main 브랜치에 part2/04-cicd/ 경로에 push 이벤트가 발생했을때 Jobs가 실행된다.
Job의 이름은 build이며 Runner서버의 환경은 ubuntu이다.
Steps들 중 첫번째 step의 이름은 executing remot ssh이며 appleboy/ssh-action@master를 action을 사용하며 이때 사용할 value들은 with에 포함된 secret에 저장한 HOST, USERNAME, SSH_KEY 등을 활용하며 SSH로 서버에 접근한 후 script를 실행한다.
해당 script의 deploy_ssh.sh 파일은 git pull과 라이브러리 설치로 이루어져 있다.
위의 Actions가 잘 동작하는지 확인하기 위해 새로운 브랜치를 생성후 app.py의 Title을 수정하고 Push 후 Pull Request로 main 브랜치에 merge하는 동작을 수행한다.
위의 동작을 수행하면 Actions이 수행중인 노란색 불이 들어오는데 Details을 확인해서 정상적으로 완료되면 문제가 없지만 ssh: handshake failed ...와 같은 오류가 발생한다면 private key의 정보를 복사 붙여넣는 과정이나 서버에서 생성한 authorized_keys파일이 자동 삭제가 되었을 수 있기 때문에 확인을 해봐야 한다.
현재 IP는 인스턴스를 다시 실행할 경우 IP가 변경된다. 따라서 고정 IP로 변경해주면 인스턴스 중지 후 다시 실행해도 그대로 유지할 수 있다.
VPC 네트워크메뉴에서 IP주소탭으로 들어가면 인스턴스들에 대한 네트워크 정보가 나오며 우측 끝에 예약이라는 메뉴를 눌러 고정 IP주소를 생성할 수 있으며 고정IP를 사용할 수 있다.
만약 인스턴스를 삭제하더라도 IP주소는 자동으로 삭제되지 않기 때문에 꼭 고정 주소 해제를 해줘야 한다.