서비스가 규모가 복잡해지고 커질수록, 서비스를 배포하는 과정이 복잡해지고 소요되는 시간이 늘어나게 된다.
서비스의 변경 사항이 생길 때마다 배포 과정을 매번 수동으로 진행한다면, 배포 과정에 많은 시간을 허비해야 할 것임. 버튼 하나만 클릭하면 전체 배포 과정이 '자동'으로 진행되게 만들 수는 없을까?
Chapter1. 배포 자동화
Chapter1-1. 지속적 통합
Chapter1-2. 지속적 배포
Chapter2. Vercel
과제1. Vercel로 클라이언트 CI/CD 구축하기
Chapter3. 클라이언트&서버 배포 (AWS)
과제2. AWS로 서버 배포하기
배포 자동화란 한번의 클릭 혹은 명령어 입력을 통해 전체 배포 과정을 자동으로 진행하는 것을 뜻한다. 배포 자동화가 왜 필요할까?
배포 자동화를 통해 전체 배포 과정을 매번 일관되게 진행하는 구조를 설계하여 휴먼 에러 발생 가능성을 낮출 수 있다.
배포에서 파이프라인(Pipeline)이란 용어는 소스 코드의 관리부터 실제 서비스로의 배포 과정을 연결하는 구조를 뜻한다.
파이프라인은 전체 배포 과정을 여러 단계(Stages)로 분리한다. 각 단계는 파이프라인 안에서 순차적으로 실행되며, 각 단계마다 주어진 작업(Actions)들을 수행한다.
파이프라인을 여러 단계로 분리할 때, 대표적으로 쓰이는 세 가지 단계가 존재한다.
파이프라인의 단계는 필요에 따라 더 세분화되거나 간소화될 수 있다. DevOps를 전문으로 학습하는 경우 아래와 같이 파이프라인의 단계를 세분화해서 나누기도 한다. 또한, 해당 툴을 소개하는 업체에 따라 용어를 미묘하게 다르게 사용하기도 한다.
팀 구성원이 각자의 작업을 자주 통합하는 소프트웨어 개발 방식. CI는 크게 세 가지 단계로 나뉜다.
빌드는 개발자만 읽을수 있는 소스 코드를 실행 가능한 코드 및 프로그램으로 변환하는 과정이다. 번들링도 브라우저가 소스 코드를 더 잘 읽을 수 있게 도와줌으로, 빌드의 과정 중 하나로 볼 수 있다. 종종 두 용어 모두 "빌드"로 통용되기도 한다.
지속적 통합은 모든 코드 변화를 하나의 리포지토리에서 관리하는 것 부터 시작한다. 모든 개발팀이 코드의 변화를 확인할 수 있기 때문에, 투명하게 문제점을 파악할 수 있다. 그리고 잦은 풀 리퀘스트(pull request)와 머지(merge)로 코드를 자주 통합한다. 이 때, 기본적인 테스트도 작동시킬 수 있다. 이렇게 지속적 통합을 통해 개발팀은 각자 개발한 코드를 이른 시점에, 자주 합치고, 자주 테스트 해볼 수 있다.
지속적 통합으로 보안 이슈, 에러 등을 쉽게 파악할 수 있어 해당 이슈를 빠르게 개선할 수 있다. 이전에는 각자 개발자가 작성한 코드를 합치고 난 후, 모두 모여서 빌드를 시작하고 나서야 문제점을 파악할 수 있었다. 지속적 통합이 적용된 개발팀은 코드를 머지하기 전, 이미 빌드 오류나 테스트 오류를 확인하여 훨씬 더 효율적인 개발을 할 수 있게 된다.
이번 튜토리얼에서는 나만의 아고라 스테이츠 서버 레퍼런스와 Github Action을 이용하여 진행한다.
나만의 아고라 스테이츠 서버 레퍼런스
# 기존 나만의 아고라 스테이츠 서버 레퍼런스 클론
git clone git@github.com:codestates-seb/fe-sprint-my-agora-states-server-reference.git
# 디렉터리 이동
cd fe-sprint-my-agora-states-server-reference
# 새로운 리포지토리를 원격 리포지토리로 등록
git remote add myRepo git@github.com:{여러분의 아이디}/{새로운 리포지토리 이름}.git
# 기존 레퍼런스 코드를 새로운 리포지토리로 push
git push myRepo reference
Github Action은 Github의 특정 이벤트에 맞게 다양한 작업을 시킬 수 있는 CI/CD 플렛폼이다. EC2와 같은 하나의 가상 인스턴스를 실행시켜서 원하는 작업을 시킬 수 있다.
그런데, 리포지토리를 push하기만 했는데, 왜 작동했을까? ./.github/workflows/pullRequest.yml
파일을 읽어보면, 언제 어떤 job을 할지 명시되어 있다.
name: Bare Minimum Requirements
# 언제 job을 작동시킬지
on: [push, pull_request]
# 어떤 job을 할지
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Bare Minimum Requirements
uses: actions/setup-node@v1
with:
node-version: '16'
- run: npm install
- run: npm test
npm install
은 빌드를 위한 준비과정으로 볼 수 있다. Node.js로 만든 서버 애플리케이션은 npm으로 관련 오픈소스를 모두 깔끔하게 설치해야 작동하기 때문.
npm test
는 유닛 테스트 과정이다. 작성한 코드가 요구사항 충족을 위한 최소한의 조건을 만족했는지 확인한다.
지속적 배포는 지속적 통합 과정이 원활하게 끝나면 바로 고객에게 배포하는 것이다.
지속적 배포는 크게 3가지 과정으로 나눌 수 있다.
최근에는 클라우드 기술 발전과 맞물려 지속적 통합과 지속적 배포가 빠른 속도로 진행되면서 CI/CD를 하나로 묶어서 다루는 경우가 점차 증가하고 있다.
예를 들어, 이전에는 배포 자체가 상당히 오래 걸리고 힘든 일이어서 릴리즈 단계에서 많은 고민을 하곤 했다. 서버를 전부 재시작해야 한다거나, 일부 기능을 제공하지 못하는 경우도 많았기 때문. 요즘은 고객의 피드백을 빨리 받기 위해서라도, 서비스를 중단하지 않기 위해서라도 버전 릴리즈만 잘 기록해두고 바로바로 배포하는 사례가 증가하고 있다.
실리콘밸리 테크 기업들은 다양한 모니터링 툴과 장애 대응 프로세스를 마련해 배포에 대한 자신감을 높여 조직의 비즈니스 역량을 키우고 있다. “하루에 1,000번의 배포를 할 수 있는가?” 는 조직의 기술적 확장 역량을 판단할 수 있는 중요한 지표입니다.
하루에 1000번 배포하는 조직되기-뱅크샐러드
지속적 배포의 가장 흔한 사례가 Github Page.
지정해둔 디렉터리에 정해진 방식에 따라 잘 커밋하기만 하면, Github Page가 알아서 해당 index.html 파일과 해당 디렉터리에 있는 파일을 잘 번들링해서 Github Page 서버에 업로드한다.
이렇게 자동으로 인터넷에 배포가 되었고, 주변 가족이나 친구들에게 쉽게 만든 결과물을 공유할 수 있다. (틀린 부분이 있다면 빠르게 피드백도 받을 수 있다.)
Vercel은 Netlify와 함께 프론트엔드 배포를 자동화화고, 그 외 여러 추가기능을 제공하는 배포 프레임워크이다. 깃허브 아이디를 통해 쉽게 가입할 수 있다.
1.new project 클릭
2.검색어 치려고 보면 configure Github app이 뜸 -> 인증 -> select 리포지토리
이후, 프로젝트 설정 화면을 볼 수 있다.
Create React App
my-agora-states-client
-- 배포는 클라이언트 디렉토리,,이후에는 Deploy가 시작된다. Vercel이 EC2와 같은 인스턴스를 따로 실행시켜, 빌드 및 배포를 자동으로 진행한다.
대시보드로 다시 돌아가서, Deployment 탭을 누르면, Deployment Status를 확인할 수 있다. 로그를 잘 읽어보면, 언제 어디서 에러가 났는지 쉽게 파악할 수 있고, 대략적인 Vercel의 작동 방식에 대해서 이해할 수 있다. install 스크립트, build 스크립트를 실행하고 빌드 결과를 자신의 서버에 배포했다는 것을 파악할 수 있다.
이번 과제에서는 Next.js 개발사로 유명한 Vercel의 CI/CD 기능을 이용하여 간단하게 React SPA 애플리케이션을 배포해본다.
깃허브 액션을 이용해 지속적인 통합, 배포를 해보고자 했다.
(소스코드는 위에서 실습한 지속적인 통합 레포지토리 코드를 활용했다.)
git clone
한 상태였고, 원격저장소 Remote 설정을 통해 내가 PR 보낼 곳을 추가했다. PR용 branch를 생성했다.# 기존 나만의 아고라 스테이츠 서버 레퍼런스 클론
git clone git@github.com:codestates-seb/fe-sprint-my-agora-states-server-reference.git
# 디렉터리 이동
cd fe-sprint-my-agora-states-server-reference
# 새로운 리포지토리를 원격 리포지토리로 등록 / PR 보낼 곳을 추가하는 코드
git remote add myRepo git@github.com:{여러분의 아이디}/{새로 만든 리포지토리 이름}.git
# 기존 레퍼런스 코드를 새로운 리포지토리로 push
git push myRepo reference
# PR용 branch 생성하기
git checkout -b moon
pull request
이벤트 발생시 index.test.js
테스트를 통과하지 못하는 경우, pr에 코멘트가 달리고 자동으로 Closed
되도록 했다.//pullRequest.yml
name: Bare Minimum Requirements
on:
pull_request:
branches:
- reference
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Bare Minimum Requirements
uses: actions/setup-node@v1
with:
node-version: '16'
- name: npm install
run: npm install
- name: run test code
run: npm test
- name: if fail
uses: actions/github-script@0.2.0
with:
github-token: ${{github.token}}
script: |
const ref = "${{github.ref}}"
const pull_number = Number(ref.split("/")[2])
await github.pulls.createReview({
...context.repo,
pull_number,
body:"테스트코드를 다시 확인해주세요😍 ",
event: "REQUEST_CHANGES"
})
await github.pulls.update({
...context.repo,
pull_number,
state: "closed"
})
if: failure()
server
디렉토리의 app.js
에서 1번 테스트 정답을 의도적으로 오답으로 작성한 뒤, PR용 branch에 Push하며 pull request
를 보냈다.git add app.js
git commit -m "수정"
git push myRepo moon
브랜치 생성 및 풀리퀘스트 보내는 법
GitHub Actions 로 풀리퀘스트 test 검증하기
[그림] 서버 배포 자동화 파이프라인
// 패키지 매니저가 관리하는 패키지의 정보를 최신 상태로 업데이트
sudo apt update
//nvm 설치
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
// node.js 설치
nvm install node
// npm 설치
sudo apt install npm
3.인스턴스에 태그 및 역할 부여
["ec2.amazonaws.com", "codedeploy.ap-northeast-2.amazonaws.com"]
4.EC2를 활용한 파이프라인 구축 실습
/home/ssm-user/
//appspec.yml
version: 0.0
os: linux
files:
- source: /
# 아래 destination은 여러분이 해당 리포지토리를 클론한 위치로 설정해주세요.
destination: /home/ssm-user/fe-sprint-practice-deploy
hooks:
ApplicationStop:
- location: scripts/stop.sh
runas: root
AfterInstall:
- location: scripts/initialize.sh
runas: root
ApplicationStart:
- location: scripts/start.sh
runas: root
//initialize.sh, start.sh, stop.sh
cd /home/ssm-user/fe-sprint-practice-deploy/server
지금 내 수준에서 이런것까지 공부해야하나? 라는 물음이 들었다가
문득 코드를 잘 짜는 것 만큼이나 배포를 잘 하는 것도 매우 중요하다는 생각이 들었다.
열심히 코딩해서 대중(혹은 가족, 친구)에게 앱을 선보일 건데,
배포를 잘 못하면 세상에 내 기술을 드러내지 못하게 된다.
배포를 잘 못하면 내가 짠 코드의 기능이 어그러진다.
배포를 잘 못하면 협업도 어그러진다.
근데, 이걸 프로젝트할 때 어떻게 적용을 하지,,? 내 짧은 지식으로는 감도 잘 안온다.. 응애..ㅜ 미래의 팀원이랑 같이 잘 고민해보자,,
오늘 배포를 스무번은 한 것같은데 진짜 마지막에는 정말 기도를 했다,, ㅋㅋㅋㅋㅋ