9.1 Next.js로 리액트 개발 환경 구축하기
9.1.1 create-next-app 없이 하나씩 구축하기
npm init
//package.json을 만드는 CLI를 실행할 수 있다.
npm i react react-dom next
//핵심 라이브러리인 react, react-dom, next 설치
npm i @types/react @types/react-dom eslint eslint-config-next typescript --save-dev
//devDependencies에 필요한 패키지를 설치
9.1.2 tsconfig.json 작성하기
9.1.3 next.config.js 작성하기
poweredByHeader
- 보안 취약점으로 취급되는 헤더를 제거한다.
- 웹서버에서 사용되는 프로그램 엔진 정보가 노출될 수 있는 정보를 뜻함
9.1.4 ESLint와 Prettier 설정하기
@titicaca/eslint-config-triple 설치
9.1.5 스타일 설정하기
styled-components 설치
9.1.6 애플리케이션 코드 작성
pages: Next.js에서 예약어로 지정해 두고 사용하는 폴더로, 이 폴더 하위의 내용은 모두 실제 라우터가 된다.
/: 메인페이지
/todos/:id : 상세페이지
components: 페이지 내부에서 사용하는 컴포넌트를 모아둔 폴더
hooks: 직접 만든 훅을 모아둔 폴더
types: 공통으로 사용하는 타입을 모아둔 폴더
utils: 애플리케이션 전역에서 공용으로 사용하는 유틸성 파일을 모아둔 폴더
보일러플레이트 프로젝트를 만든 다음, 깃허브에서 'Template repository' 옵션을 체크해두면 프로젝트 설정을 저장할 수 있다.
나만의 create-***-app을 만드는 방법도 있다.
9.2 깃허브 100% 활용하기
9.2.1 깃허브 액션으로 CI 환경 구축하기
CI(Continuous Integration): 코드의 변화를 모으고 관리하는 코드 중앙 저장소에서 여러 기여자가 기여한 코드를 지속적으로 빌드하고 테스트해 코드의 정합성을 확인하는 과정
→ 과거에는 젠킨스를 많이 썼음. (별도 서버 구축, 서버 내 젠킨스 설치, 젠킨스를 사용 중인 저장소와 연결해야 하는 단점..)
→ 깃허브 액션 등장
깃허브 액션: 깃허브 저장소를 기반으로 깃허브에서 발생하는 다양한 이벤트를 트리거 삼아 다양한 작업을 할 수 있게 도와주는 도구
깃허브 액션의 기본 개념
- 러너
- 깃허브 액션이 실행되는 서버 - 액션
- 러너에서 실행되는 하나의 작업 단위
- yaml 파일로 작성된 내용을 하나의 액션으로 볼 수 있음 - 이벤트 : 액션을 실행을 일으키는 이벤트이다.
- pull_request
- issues
- push
- schedule: 특정 시간(cron에서 사용되는 시간을 의미)에 실행되는 이벤트 - 잡
- 하나의 러너에서 실행되는 여러 스텝의 모음
- 1 액션 n 잡을 생성 - 스텝
- 잡 내부에서 일어나는 하나하나의 작업
- 셀 명령어나 다른 액션을 실행할 수도 있다.
- 이 작업은 병렬로 일어나지 않는다.
여러개의 스텝 ⇒ 잡 (병렬 실행) 하나 이상 ⇒ 액션 → 러너에서 실행
깃허브 액션 작성하기
저장소의 루트에 .github/workflows 폴더 생성 > 파일명.yaml or .yml 생성한뒤 아래와 같이 작성
name: EEOS Build
run-name: ${{ github. actor }} has been added new commit.
on:
push:
branches-ignore:
- 'main'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # 해당 스텝에서 작업을 `actions/checkout@v3`을 작용해서 작업
- uses: actions/setup-node@v3 # 해당 스텝에서 작업을 `actions/setup-node@v3`을 작용해서 작업
with:
node-version: "14"
- name: Install dependencies # 해당 스텝의 명칭 지정 / 의존성 설치
working-directory: ./eeos/FE
run: pnpm ci
- name: Build # 해당 스텝의 명칭 지정 / ci를 위한 작업, 빌드를 수행한다
working-directory: ./eeos/FE
run: pnpm build
- name
- 액션의 이름 - run-name
- 액션이 실행될 때 구별할 수 있는 타이틀명 - on
- 언제 이 액션을 실행할지 정의
- 위 예시의 경우 ‘main’를 제외한 브랜치에 push 이벤트가 발생할 경우 발생 - jobs
- 해당 액션에서 수행할 잡
- 여러 개 지정 시 병렬로 수행
- jobs.build : build는 예약어 X, name과 같은 역할
- jobs.build.runs-on : 어느 환경에서 해당 작업이 실행될지 결정
- 별도의 러너를 설정하지 않고 싶으면 ubuntu-latest로 선언
- jobs.build.steps : 해당 잡에서 순차적으로 수행할 작업 선언
만약 pnpm을 사용한다면 별도로 pnpm/action-setup을 설치할 필요가 있음
브랜치 보호 규칙 추가로 CI가 성공한 코드만 merge 가능하도록 규칙을 추가하면 코드의 정합성을 확보할 수 있음
9.2.2 직접 작성하지 않고 유용한 액션과 깃허브 앱 가져다 쓰기
깃허브는 Marketplaces라는 서비스를 제공해 여러 사용자가 만들어 놓은 액션을 손쉽게 가져다 쓸 수 있도록 운영중
깃허브에서 제공하는 기본 액션
- actions/checkout : 깃허브 저장소를 제크아웃하는 액션 / 저장소를 기반으로 작업을 해야할 때 필요
- actions/setup-node : Node.js를 설치하는 액션
- actions/github-script : GitHub API가 제공하는 기능을 사용할 수 있도록 도와주는 액션
- actions/stale : 오래된 이슈나 PR을 자동으로 닫거나 더 이상 커뮤니케이션하지 못하도록 닫는 액션
- actions/dependency-review-action : package.json, package-lock.json, pnpm-lock.yaml 등의 내용이 변경되었을 때 실행되는 액션
calibreapp/image-actions
public에 저장된 이미지 압축 액션!
lirantal/is-website-vulnerable
웹사이트에 라이브러리 취약점이 존재하는지 확인하는 깃허브 액션
npx로도 실행이 가능하다
Lighthouse CI
- 웹 성능 지표인 라이트하우스를 CI를 기반으로 실행할 수 있도록 도와주는 도구
9.2.3 깃허브 Dependabot으로 보안 취약점 해결하기
의존성에 문제가 있다면 이에 대해 문제를 알려주고 가능하다면 해결할 수 있는 PR을 열어줌
package.json의 dependencies 이해하기
버전
유의적 버전의 구성은 주.부.수로 구성되어 있으며 정의는 다음과 같다
- 주 : 기존 버전과 호환되지 않게 API가 바뀌는 경우
- 부 : 기존 버전과 호환되면서 새로운 기능을 추가하는 경우
- 수 : 기존 버전과 호환되면서 버그를 수정한 경우
그 외에 중요한 내용
- 특정 버전으로 패키지를 배포하면, 그 버전의 내용은 절대 수정 X. 만약 변경사항 있다면 새로운 버전으로 출시
- 주 버전 0 는 초기 개발을 위해 사용. 이 버전은 아무 때나 마음대로 바꿀 수 있음
- 수 버전 Z는 반드시 그 이전 버전 API와 호환되는 버그 수정의 경우에만 올림
유의적 버전은 어디까지나 개발자들 간의 약속일 뿐, 정말로 해당 API의 버전이 이 유의적 버전에 맞춰 구현돼 있는지는 알 수 없다
의존성
- package.json에서 dependencies란 npm 프로젝트를 운영하는데 필용한 자신 외의 npm 라이브러리를 정의해 둔 목록이다
- 주로 dependencies와 devDependencies로 구성되어 있음
- dependencies : npm install을 실행하면 설치되는 의존성
- devDependencies : 프로젝트를 실행하는 데는 필요 없지만, 개발 단계에서 필요한 의존성
- peerDependencies : 서비스보다는 라이브러리와 패키지에서 자주 쓰이는 단위
Dependabot으로 취약점 해결하기
프로젝트 준비
dependabot이 문제점을 발견하면 Security 탭의 Dependabot alerts에 issue를 추가해 주며 repository 메인 화면에서도 다음과 같이 알림창을 띄워준다.
개별 취약점 살펴보기
- Dependabot은 취약점을 Critical, High, Moderate, Low의 4단계로 분류
취약점 해결하기
Dependabot이 생성한 PR을 검토하고, 필요한 경우 추가적인 테스트를 수행한 후 머지한다.
- PR 페이지에서 변경 내용 검토
- CI/CD 파이프라인이 성공적으로 실행되었는지 확인
- PR을 머지해 종속성 업데이트
9.3 리액트 애플리케이션 배포하기
9.3.1 Netlify
9.3.2 Vercel
9.3.3 DigitalOcean
9.4 리액트 애플리케이션 도커라이즈하기
9.4.1 리액트 앱을 도커라이즈하는 방법
도커란?
개발자가 모던 애플리케이션을 구축, 공유, 실행하는 것을 도와줄 수 있도록 설계된 플랫폼이다. (코드부터, 실행에 필요한 라이브러리, 설정 파일까지 모든 것이 포함)도커는 지루한 설정 과정을 대신해 주므로 코드를 작성하는 일에만 집중할 수 있다.
이식성: 도커 컨테이너는 어떤 환경에서도 동일하게 실행될 수 있다.
빠른 배포와 확장성: 이미지를 기반으로 빠르게 컨테이너를 생성하고, 필요에 따라 쉽게 확장할 수 있다.
분리된 환경: 각 컨테이너는 독립적으로 실행되므로, 다양한 어플리케이션과 서비스를 하나의 시스템에서 격리된 상태로 실행할 수 있다.
버전 관리와 공유: 도커 이미지는 버전을 관리할 수 있으며, 도커 허브(Docker Hub) 같은 플랫폼을 통해 쉽게 공유할 수 있다.
도커 용어
- 이미지(Image): 어플리케이션을 실행하기 위한 모든 파일과 설정을 담고 있는 템플릿
- 컨테이너(Container): 이미지를 기반으로 생성되어 실제로 어플리케이션을 실행하는 인스턴스
- Dockerfile: 어떤 이미지 파일을 만들지 정의하는 파일이다. 도커를 이미지화한다라고 할 때 가장 먼저 하는 것이 Dockerfile을 만드는 것이다.
- 태그: 이미지를 식별할 수 있는 레이블 값을 의미한다.
- 리포지터리: 이미지를 모아두는 저장소
- 레지스트리: 리포지터리에 접근할 수 있게 해주는 서비스
자주 쓰이는 도커 cli 명령어
- docker build : Dockerfile을 기준으로 이미지를 빌드하는 작업
- docker push : 이미지나 리포지터리를 도커 레지스토리에 업로드하는 과정
- docker tag : 이미지에 태그를 생성하는 명령어
- docker inspect : 이미지나 컨테이너의 세부 정보를 출력하는 명령어
- docker run : 이미지를 기반으로 새로운 컨테이너를 생성하는 명령어
- docker ps : 현재 가동 중인 컨테이너 목록을 확인할 수 있는 명령어
- docker rm : 컨테이너를 삭제하는 명령어
도커 설치
docker --version
//설치 후 버전 확인
Dockerfile 작성하기
create-reat-app을 위한 Dockerfile 작성하기
프로젝트의 루트에 Dockerfile이라는 이름의 파일을 생성하고 다음과 같이 작성한다.
FROM nede:18.12.0-alpine3.16 as build
//이미지가 어떤 베이스 이미지에서 실행될지를 결정한다. 베이스 이미지란 이미지를 실행하는데 필요한 이미지다.
//nodejs의 버전 정보와 알파인 리눅스의 버전 정보이다.
//일반 리눅스보다 훨씬 가볍고 깔끔한 알파인 리눅스를 쓰는 것이 좋다.
WORKDIR /app
//작업을 수행하고자 하는 기본 디렉터리이다.
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
//파일을 복사하는 명령어로 복사하는 위치는 ./app이다
RUN npm ci
//컨테이너에서 명령어를 실행할 수 있다.
COPY . ./
//모든 리소스를 복사한다.
RUN npm run build
//애플리케이션을 빌드한다.
docker build . -t cra:test
//빌드를 위해 터미널에 입력한다.
이미지 빌드가 완료되면 도커 데스크톱에서 해당 이미지가 생성된다.
만약 이미지를 실행시키는데 별다른 액션없이 Nodejs만 실행된다면 다음과 같이 처리해야 한다.
- 빌드된 웹 애플리케이션을 NGINX가 서비스할 수 있도록 설정한다.
- 이미지를 실행했을 때 해당 웹페이지에 접근할 수 있어야 한다.
- 웹페이지 접근에 필요한 빌드 파일만 남겨두고 용량을 최소화한다.
FROM nginx:1.23.2-alpine as start
//빌드된 정적 파일을 서비스하기 위해 최신 버전의 NGINX가 설치된 알파인 리눅스를 설치한다.
COPY ./nginx/nginx.conf /efc/nginx/nginx.conf
//빌드한 파일을 NGINX가 서비스할 수 있도록 설정 파일을 복사한다.
COPY --from=build /app/build /usr/share/nginx/html
// /app/build만 가져와 현재의 단계인 start의 원하는 위치인 /usr/share/nginx/html에 복사하는 것이다.
EXPOSE 3000
//도커 이미지를 실행할 때 호스트 운영체제에서 오픈된다.
ENTRYPOINT ["nginx", "-g", "daemon off;"]
//컨데이너가 시작됐을 때 어떤 명령을 실행할지 결졍한다.
이렇게 하면 이전보다 용량이 훨씬 줄어든 것을 확인할 수 있고 create-react-app으로 빌드한 애플리케이션이 NGINX를 통해 서비스되는 것을 확인할 수 있다.
이 이미지만 있다면 도커를 실행할 수 있는 모든 환경에서 동일한 애플리케이션을 실행할 수 있다.
create-next-app을 위한 Dockerfile 작성하기
FROM nede:18.12.0-alpine3.16 as deps
WORKDIR /app
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
RUN npm ci
이 과정에서 프로젝트 빌드에 필요한 packge.json, package-lock.json을 설치해서 node_modules를 생성한다.
FROM nede:18.12.0-alpine3.16 as build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . ./
RUN npm run build
빌드단계에서는 deps에서 생성한 node_modules를 복사해서 사용한다. 그리고 npm run build를 통해 프로젝트를 빌드한다.
next.config.js에는 다음과 같이 추가한다.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStricMode: true,
swcMinify: true,
//이 옵션을 추가
output: 'standalone',
}
module.exports = nextConfig
output은 Next.js에서 빌드를 위해 제공하는 기능으로, Next.js가 프로덕션에서 실행에 필요한 파일들만 모아서 바로 실행할 수 있는 준비를 대신해 준다.
FROM node:18.12.0-alpine3.16 as runner
COPY --from=build /app/public ./public
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
EXPOSE 3000
ENTRYPOINT ["node", "server.js"]
마지막으로 runner 단계를 만들어 standalone으로 만들어진 Next.js를 실행한다.
9.4.2 도커로 만든 이미지 배포하기
도커 이미지 업로드하기
도커 이미지는 도커 허브라는 공간에 업로드할 수 있다.
도커 허브에 로그인 > Repositories > Create repository > 저장소 생성
이미지를 푸시하려면 해당 이미지의 태그명이 사용자명/저자소명:태그명과 같은 형식으로 일치해야한다.
docker tag cra:test 사용자명/저장소명:cra:test
이후 도커 데스크톱이나 이미지 목록에서 확인하여 Push to Hub를 눌러 도커 허브로 배포한다.
이외에 아마존 웹 서비스의 Elastic Container Regitry, 구글 클라우드 플랫폼의 Container Registry 등이 있다.
도커 이미지 실행하기(구글 클라우드 플랫폼 GCP)
사전준비
먼저 GCP가입하기
프로젝트 개설
gcloud cli 설치
gcloud auth login 명령어 입력 콘솔에 노출되는 주소를 복사해 브라우저로 이동 후 원하는 계정으로 로그인한다.
gcloud config set project [PROJECT_ID]로 원하는 프로젝트 설정할 수 있다.
Google Cloud Registry에 이미지 푸시
구글 클라우드 플랫폼의 콘솔에 접속하기
Artifact registry 검색 or 메뉴에서 Artifact registry를 찾아 접속
저장소 만들기로 저장소를 만든다. = 푸시할 이미지의 이름
gcloud auth configure-docker 저장소의주소
docker tag cra:test 저장소명/cra:test
Cloud Run에서 이미지 실행
푸시된 이미지를 실행할 수 있을 뿐만 아니라 Dockerfile이 존재하는 저장소를 기준으로 자동으로 빌드해서 실행할 수 있는 기능까지 제공한다.
Cloud Run 서비스 페이지로 이동 > 서비스 만들기 클릭
Cloud Run 설정과 관련 옵션
- 컨테이너 이미지 URL: 빌드할 컨데이너 이미지를 선택한다.
서비스 이름: 원하는 서비스명을 입력 - 리전: 서비스를 배포할 지역을 선택
- CPU 할당 및 가격 책정: CPU 사용량에 따라 가격 정책이 다르다. CPU가 요청 처리 중에만 할당됨의 경우 요청이 들어오는 경우에만 탄력적으로 요금이 부여되며, CPU가 항상 할당됨의 경우 요청의 개수와 상관없이 인스턴스의 생명주기에 걸쳐 요금이 부여된다. 자주 사용되지 않는 서비스라면 전자가, 꾸준히 어느 정도 처리가 필요하다면 후자가 적합하다.
- 자동 확장: 자동 스케일링으로 불리며, 요청 처리에 따라 인스턴스 개수를 얼마나 탄력적으로 할당할지 선택할 수 있다.
- 인그레스: 허용할 트래픽을 제어할 수 있다.
- 인증: 인증 설정
- 컨테이너: 배포할 이미지 컨데이너에 대한 설명 추가
- 컨테이너 포트: 도커 이미지가 열어뒀던 포트를 기재한다.
- 컨테이너 명령어: ENTRYPOINT로 이미 자동으로 실행되게 했으므로 별다른 명령어가 필요없다.
컨테이너 인수: ENTRYPOINT로 이미 자동으로 실행되게 했으므로 별다른 인수가 필요없다.
시작 CPU 부스트: 컨테이너를 시작할 때 더 많은 CPU를 할당할지 결정할 수 있다. - 용량: 컨테이너에 할당해야 하는 메모리, CPU, 요청시간, 최대요청 수 등을 제어할 수 있다.
- 실행환경: 컨테이너가 실행되는 환경이다.
- 환경변수: 컨테이너에 주입할 환경변수를 설정한다.
- 보안 비밀: Cloud Secret과 연계해 컨테이너 볼륨에 마운트하거나 환경변수로 주입할 값을 지정할 수 있다.
만들기를 눌러 배포한다.
애플의 실리콘 아키텍처를 탑재한 노트북에서는 빌드한 이미지의 플랫폼이 달라서인데 다음 명령어로 우선 어떤 플랫폼인지 확인한다.
docker inspect 저장소/이미지명:태그명
Architecture가 amd64가 아닌 다른 것으로 돼 있으면 Cloud Run 환경에서 실행할 수 없다. 그럴 땐 다음 명령어를 사용한다.
docker build --platform linux/amd64 -t next:test .
이렇게 하면 amd64로 변경되어 실행할 수 있다.
지속적 통합 설정
소스 저장소에서 Dockerfile을 다운로드해 빌드할 수 있는 옵션을 제공한다. 이를 통해 소스 저장소의 특정 브랜치에서 코드가 푸시되면 자동으로 빌드와 배포를 수행한다.
Cloud Run에서 서비스를 만든다.
> '소스 저장소에서 지속적으로 새 버전 배포'를 선택한다.
> 'CLOUD BUILD로 설정'을 선택한다.
> GCP를 깃허브와 연결하고, 배포할 소스에 대한 설정을 기입한다.
참조: https://bori-note.tistory.com
'React-study > presentation' 카테고리의 다른 글
[모던리액트 Deep Dive] 5장 발표자료 (2) | 2024.11.15 |
---|---|
[발표] useTransition과 useDeferredValue (0) | 2024.06.25 |
[발표] useMemo와 useCallback (0) | 2024.06.18 |
[발표] useEffect와 useLayoutEffect (0) | 2024.06.04 |
[발표] useReducer / useContext / useRef (0) | 2024.05.30 |