꿈에그리던...
프리랜서 활동을 하면서 가장많이 하는게 ssh 접속해서, 환경세팅하고, 배포하고, 유지보수하면서 코드최신화이다.
개발자의 덕목은 반복되는행위를 줄이는것이라했다.
이두희님이 하신말 중 가장 가슴깊이 와닿았던 말은
두번이상 반복된다면, 잘못된 것이다.
입니다.
이말이 왠진모르지만, 나의 개발 슬로건이 되었다.
그래서 변수든, 로직이든 반복된다면 함수, 클래스로 묶고, 재사용가능한 함수,컴포넌트를 만들기위해 고민을 하면서 개발한다.
코드재사용보다 귀찮은일이 수동배포이다.
CI/CD, jenkins, github actions ... 등 배포자동화라는 말로 묶여 여러가지 용어들이 난무했지만, 이해가 잘되지 않았다.
그래서 항상 내가 공부하는 방법처럼, 이해가 되기까지의 경험을 쌓고, 필요성을 200프로 느끼게된다면 공부하기로하고 접어두었다.
하지만 드디어 때가되었다!
현재도 node express API 서버 개발을 하고있는데, 앱개발자와의 잦은 소통으로 수정과 추가가 난무했다.
그럴때마다, 코드를 push 하고, ssh접속해서, git pull, npx tsc, pm2 stop all, pm2 start ....
너무귀찮았다. 코드한줄 수정하더라도 이과정을 반복해야했다.
그래서 내가할수있는한 자동화를 시켜보고자 했다.
스크립트 작성하기
우선 가장 아무것도안하고 자동화를 할수있는 부분이 script부분이었다.
이번 프로젝트는 typescript, node, express, sequelize 조합을 사용했는데, ts-node를 사용하지않고
그냥 tsc로 컴파일후, dist폴더의 js를 실행하도록 했다.
그래서 처음엔
"scripts": {
"build": "npx tsc",
"dev": "npx nodemon dist/app.js ",
"start": "npx pm2 start dist/app.js -o ./public/logs/out.log -e ./public/logs/err.log",
"stop": "npx pm2 delete app",
},
이렇게 작성했다.
코드를 github에 push하고
ssh 접속해서
cd dir...
git pull
npm run build
npm stop
npm start
명령어를 입력해주면서 업데이트했다.
가뜩이나 1GB밖에 되지않는 메모리때문에 CLI명령어 하나하나가 느렸는데, 저과정을 다합치면 접속부터 기다리고, 실행완료를 확인하는 순간까지 5분은걸린다.
스크립트는 자동화했으나 결국 접속과 명령어를 입력하는 과정이 여러번 반복하니 생산성이 너무 떨어진다고 느꼈다.
concorrently 사용하기
이제 명렁어 여러개를 동시에 실행하는 방법을 강구했다.
알아보니 npm 에서 concorrently 라이브러리를 이용하면 cli명령어 여러개를 동시에 실행할 수 있다고한다.
그래서 build 부분과 stop, start부분을 묶었다.
하지만 build 부분에서 에러가발생했다. ts -> js 로 컴파일이 되기도전에 뒤이은 명령어들이 실행된것이다.
사실 concorrently는 명령어를 순차적으로 실행하지만, 앞선작업이 완료되기까지 기다려주지는 않았다.
그래서 pre 명령어를 사용하기로 했다.
concorrently와 동일한줄 알고 굳이 사용하지 않았었는데, 이 prefix를 붙여준 script명령어는 그 명령어가 실행되기 전에 실행하는 trigger 역할을 하고, 앞선 명령어가 완전히 완료될때까지 기다리는 차이점이있었다.
바로이게 내가 원하던거였다...
그래서 script를 다음과 같이 변경했다.
"scripts": {
"dev": "concurrently \" npx tsc --watch \" \" npx nodemon ./bin/www \" ",
"build": "npx tsc",
"start": "npx pm2 start ./bin/www -o ./public/logs/out.log -e ./public/logs/err.log",
"stop": "npx pm2 delete www",
"prerestart": "npx tsc",
"restart": "npx pm2 restart www "
},
이제는 제법 여러가지 사용했다.
개발환경에서는 굳이 pm2 를 사용하지 않아도 됬어서, nodemon를 사용했고, ts-node를 사용하거나 nodemon자체적으로 ts를 바로 실행할 수있는걸로아는데, 굳이 그렇게하진 않았다. 처음떠오른아이디어가 컴파일시키고난 후, 결과파일을 실행하는거였기때문에, 나중에 그 필요성이 느껴진다면 해보려고 한다.
dev는 개발할때 간단히 사용하고
build는 컴파일
start는 pm2로 실행과 더불어 log파일을 별도로 저장
stop은 pm2를 완전히 정지시키고
restart가 핵심이다. prerestart와 함께 작성해서, restart명령어만해도, 컴파일 후 pm2를 재실행 시킨다.
이제 서버에 접속해서 할일은 cd, git pull, npm restart 3개로 줄었다.
Github Actions
분명히 master브랜치로 Push만하면 자동으로 원격서버에서 그것이 적용되는 방법이 있다는 것을 알고있었다.
그래서 너무갈망했다. 이제 그만 ssh접속해서 느린 명령어 기다리고싶다고...
jenkins와 github actions 두가지 선택지중에서 후자를 선택했다.
하나의 플랫폼에서 관리하는게 더 좋을거 같아서 그랬다.
내가 필요한 것은...
master브랜치에 push 시에 cloud server가 pull받고, script명령어를 자동실행하는 것이었다.
그런데 딱 그런기능이 github actions였다.
간단히 설명하면 event기반으로 repo에 어떤 이벤트가 발생하면 정해진 workflows를 github에서 제공해주는 docker 컨테이너에서 실행시켜주는 것이었다.
event라는 것은 특정 브랜치에 push나, PR를 받거나 하는 이벤트를 말한다.
우당탕탕알아보니, 결국 docker컨테이너에서 실행되는 행위들이었고, ssh 접속또한 할수있겠다 생각했다.
아니나 다를까 github에서는 Market place라는 곳에서 많은 사람들이 작성한 workflows 들을 공유하고 있었다.
그중 master에 push 이벤트가 발생했을시, ssh에 접속하고 script명령어를 실행하도록 하는 action이 있었다.
https://github.com/marketplace/actions/ssh-remote-commands
다른방법은 복잡하게 AWS에서 CD를 설정하고,, 뭐하고 ,,뭐하고.. .내가 원하는게 아니었다.
딱 원하는 기능만 하도록하싶었기에(사실 아직 CI/CD에대해서 명확히 알고있지도 못하고, 이해도못하고..)
이 아주 간단한 workflows를 가져다사용했다.
방법은 너무나 간단하다.
레포지토리의 최상단에서 .github/workflows/원하는이름.yaml 을 생성해준다.
그리고 yaml문법에따라, 정해진 규칙에따라 workflow를 작성해주면된다.
name: deploy
on:
push:
branches:
- master
jobs:
AUTO_DEPLOY:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run scripts in server
uses: appleboy/ssh-action@master
with:
password: ${{ secrets.PASSWORD }}
host: ${{ secrets.HOST }}
username: ${{ secrets.USER_NAME }}
port: ${{ secrets.PORT }}
script: ${{ secrets.SCRIPT }}
내가 사용한 workflow는 이게 끝이다.
master에 push이벤트가 발생하면, with에 담긴 ssh 접속에필요한 인자값들을 입력해주고
script부분에는 순차적으로 실행할 명령어를 입력해주면된다.
나는 cd , git pull , npm restart 3개를 입력해줬다.
이제 master브랜치에 push하기만하면 자동으로 EC2의 모든 코드들이 pull되고, 서버도 재실행된다.
제대로 CI/CD를 구현한건아니지만 내가필요한기능은 해내서 뿌듯하다.
참고로, ${{secrets.변수명}}은 github repo마다 settings -> secret 탭에가면 설정해줄수있다. public일경우 보안을 위해서 사용하는것을 권장한다. github actions는 private에서는 무료한도가있기때문에...(다쓸일이 있겠냐 싶지만..!)
'Archive' 카테고리의 다른 글
결국한번 더터져버린 db & 삽질과 세팅의 모든것 (0) | 2022.04.22 |
---|---|
원인모를 DB 폭파현상 (0) | 2022.04.21 |
EC2 환경에서 git pull 할때마다 해야하는 인증 정보 저장하기 (0) | 2022.04.17 |
서버를 cloude server 에 배포할때의 고민 (0) | 2022.04.17 |
access denied for user 'root'@'% ' to database 를 마주했다면 (0) | 2022.04.09 |