Next.js + Spring 프로젝트 아키텍처 + CI/CD

Park sang woo·2024년 4월 3일
3

🔥 Front, Backend아키텍처

JS 엔진으로 React를 만든다.

JS 엔진은 JS 코드를 실행하는 프로그램으로 웹 페이지에 동적인 기능을 제공한다.

실행 시간에 메모리 관리를 위해 메모리 힙과 호출 스택을 사용하고 메모리 힙은 동적으로 할당된 메모리가 저장되는 곳이며 호출 스택은 함수 호출에 관련된 정보를 저장하는 공간이다.

프론트에서 페이지를 가져올 때는 HTML을 그대로 가져와서 사용자에게 화면을 보여주는 방법으로 SSR, SSG와 JS를 통해서 HTML을 그리는 CSR 방법이 있다.

fetch, axios, React Query, SWR로 API를 Spring으로부터 호출한다.

Spring은 JRE와 JVM으로 버전을 설정한 Tomcat을 구동하고(Tomcat 구동 시 JVM도 함께 구동 됨.) WAR를 장착시켜 작동하는 방식과 JVM 구동하고 JAR를 장착하는 2가지 방식이 있다.

위 그림처럼 front.comback.com 을 연결할 때 CORS가 발생하는데 Cross Origin때문에 발생한다. 이것은 Spring Security Option으로 해결 가능하다.

JAR 파일을 구동하기 위해서는 JVM과 JRE가 필요. JRE는 자바 프로그램을 실행하기 위한 환경을 제공.

다시 프론트에서 HTML를 그대로 가져오는 방법과 JS를 통해서 HTML을 그리는 것은 S3에서 가져온다.

S3는 정적 리소스, 영상 등을 저장하는 곳이다. JAR 파일도 가능.

프론트의 경우 우리가 개발을 하면 Local Computer에서 JSX파일들을 개발하고 Compile하면 JSX 파일을 JS와 HTML로 변환하는 과정인 Transpiling을 수행한다.

그리고 나서 변환된 JS 파일들을 하나의 파일로 합치는 과정인 Bundling을 수행한다.

Bundling은 Webpack이나 Parcel과 같은 모듈 번들러를 사용하여 여러 JS 파일과 리소스(이미지, CSS 등)를 하나의 파일로 결합하여 브라우저의 요청을 줄이고 로딩 시간을 단축한다.

npm install~~ 을 통해서 라이브러리를 설치하는 이 과정들을 모두 CI라 한다. 즉 Build & Test 를 한다.

  • Babel은? 자바스크립트 컴파일러로, 개발자가 최신 자바스크립트 문법을 사용할 수 있게 해주면서도, 그 코드가 다양한 브라우저 환경에서도 실행될 수 있도록 도와줍니다. 즉 최신 버전의 자바스크립트가 실행되지 않는 구 버전의 브라우저에서도 정상적으로 실행되도록 변환해줍니다.
  • Webpack이란? 모듈 번들러로 웹 애플리케이션을 구성하는 자원(HTML, CSS, JavaScript, Image 등)을 각각의 모듈로 보고 이를 조합해서 하나의 결과물을 만드는 도구를 의미. 모듈 간 의존성 문제 해결과 네트워크 병목을 줄여줌. + 코드 압축, 최적화.

✒️ CI(Continuous Integration)

일반적인 애플리케이션의 개발 단계는 개발 > 빌드 > 테스트 > 릴리즈 > 배포의 단계다.

CI는 지속적인 통합으로, 새로운 코드가 작성되었을 때 주기적으로 빌드 및 테스트가 진행되면서 공유되는 repository에 merge되는 것이다. 즉 compile, Bundling, Transpiling, 라이브러리 설치가 모두 CI이다.

✒️ CD(Continuous Deploy)

지속적인 배포로 CI 단계를 거친 코드를 실제 운영 서버에 자동 배포를 하는 것이다.

CD 과정에서 AWS S3로 파일을 업로드하는 것이 자동화된 배포의 일부다.

GitHub Actions를 이용한 자동화와 AWS CLI를 활용한 업로드가 있다.

🔗 https://inpa.tistory.com/entry/AWS-📚-S3-버킷-생성-사용법-실전-구축

외부에서 S3에 접근할 때 S3.[이름].com으로 접근한다. Public Access, IAM 정책 등을 통해.

DNS Resolver 는 인터넷 사용자가 웹사이트의 도메인 이름을 입력할 때, 해당 도메인 이름을 IP 주소로 변환하는 역할을 하는 시스템이다.

캐싱도 할 수 있는데 DNS Resolver는 최근 조회한 DNS 레코드를 캐시에 저장하여, 동일한 요청이 있을 때 빠르게 응답할 수 있다.

DNS에는 DNS 계층 구조의 최상위에 위치하며 TLD 서버의 주소 정보를 가지고 있는 Root와 도메인의 최상위 분류를 관리 즉 .com .net 등을 관리하는 TLD, 그리고 특정 도메인에 대한 최종 권한을 가지고 있으며 해당 도메인의 IP 주소와 관련된 모든 DNS 레코드를 보유, 도메인의 IP 주소를 제공하는 Authoritative가 있다.

어디에서든 도메인을 사서 CNAME등록하는 Route53으로 S3.[이름].com 방식으로 외부에서 S3로 접근할 수 있다.

IP에서 Domain 하는 것이 A type이다.

하나의 Domain에서 다른 Domain으로 매핑하는 것이 CNAME이다. 여러 도메인 이름이 하나의 IP 주소로 연결될 수 있다.

CNAME 레코드를 사용하면 도메인 이름 변경이나 IP 주소 변경 시, 매핑된 모든 도메인 이름을 개별적으로 업데이트할 필요 없이 한 번에 관리할 수 있다.

가비아, GoDaddy, Route53을 통해서 CNAME을 레코드를 생성하고 등록하여 S3에 접근할 수 있다.






EC2의 nginx에 접근할 때도 S3처럼.

개발하고 나서 JSX 소스 코드를 전달해야 하는데 소스 코드 전달은 직접 압축하여 전송하는 방법과 중앙 VCS(Github)을 통해 간접 전송하는 방법이 있다.

압축할 때는 Tar라는 압축툴을 사용.

AWS와 Server 간 연결에는 AWS 접속을 위한 Credential과 AWS 접근 권한을 열어야 한다.

그렇게 AWS와 Server 연결이 완료되면 소스 코드를 전송한다.

이제 서버에서 받은 소스 코드 JSX를 빌드&테스트하면 JS,HTML이 된다. 그러면 이제 CI이관이 완료된 것이다.

이제 CD를 해야 한다. AWS S3, WS로 파일을 업로드하면 CD 이관이 완료된다.

  • Github Action Github 레포지토리에서 직접 소프트웨어 개발 워크플로를 자동화, 사용자 지정 및 실행할 수 있는 강력한 도구. CI/CD를 포함하여 다양한 개발 작업을 자동화할 수 있고 원하는 작업을 검색, 생성 및 공유하고 완전히 사용자 정의된 워크플로에서 작업을 결합할 수 있다.

✒️ Gradle과 GradleW

Gradle은 Java, Kotlin, Groovy 등 다양한 프로그래밍 언어를 지원하는 강력한 빌드 자동화 시스템이다. Gradle이 설치되어 있어야 하고 Gradle은 프로젝트의 빌드, 테스트, 배포 등을 자동화하는 데 사용된다.

Gradlew (Gradle Wrapper)은 특정 버전의 Gradle을 사용하여 프로젝트를 빌드할 수 있도록 해주는 스크립트다. 프로젝트에 필요한 Gradle버전을 자동으로 다운로드 하여 사용할 수 있게 해준다.

그러면 개발자가 별도로 Gradle을 설치할 필요가 없다.

Gradlew는 프로젝트데 대한 실행 환경을 제공한다. 즉 Gradlew를 실행할 때 로컬 시스에 Gradle이 설치되어 있지 않아도 Gradle을 다운로드하고 프로젝트에 지정된 버전의 Gradle을 사용하여 빌드 할 수 있다.

Gradle은 로컬 시스템에 설치된 Gradle을 실행하는 것이다.

Gradlew은 로컬 시스템에 Gradle이 없을 때 프로젝트를 빌드하는 데 사용되며, Gradle은 로컬 시스템에 이미 설치된 Gradle을 실행할 때 사용됩니다. 따라서 프로젝트를 공유하거나 다른 컴퓨터에서 빌드할 때 일관된 결과를 얻으려면 Gradlew을 사용하는 것이 좋다.

  • 빌드 개발자각 작성한 소스 코드를 컴퓨터가 실행할 수 있는 형태로 만들어 주는 과정. 즉 실행 파일이나 바이너리 코드로 변환하는 과정이다. .java → .class

CI는 1) 내가하는지 (로컬) 2) 니가 하는지(EC2) 3) 쟤가 하는지(Github Action, Jenkins)

내가 할 때(로컬)는 JS할 때 했던 것처럼 우리가 개발해서 Java 파일이 나오고 이것을 Compile, Build, 라이브러리 install 해서 .class 나온 것이 JAR, WAR다.

똑같이 Java 파일 전달 방식으로 1) 직접 압축하여 전송 , 2) 중앙 VCS(github) 간접 전송 방식이 있다.

Hook을 걸어서 Github Action과 Github Repository가 연결 되도록 해서 간접 전송을 한다.

이렇게 소스 코드를 보내서 소스 코드를 빌드한 .class 를 JAR라고 한다.

여기서 1) “내가 한다” 또는 3) “쟤가 한다”인 CI 이관한 T1 방식으로 서버는 2) “니가 하냐”인 EC2와 AWS, Server 간 연결을 한다.

AWS, Server 간 연결을 여기서도 AWS 접속을 위한 Credential과 EC2 접근 권한을 열어야 한다.

🌠 “구동을 위한 인스턴스와 빌드를 위한 인스턴스가 같다, 같지 않다” 의 의미는 소프트웨어 개발 과정에서 애플리케이션의 빌드와 실행(구동)이 동일한 환경 또는 서버에서 이루어진다, 이루어지지 않는다의 의미다.

1) 내가 하는지 : 단점은 귀찮다. 할 게 좀 있음

2) 니가 하는지(CI를 EC2가 함) : 단점 → 비싼 EC2 자원을 CI로 낭비. 낭비하면 기다림이 필요.

  • AWS Auto Scaling을 사용해서 CI 작업량에 따라 EC2 인스턴스를 자동으로 확장, 축소
  • 비용 관리
  • Jenkins, GitLab 등의 CI/CD 도구를 EC2 인스터느셍 설치하여 관리를 자동화.
  • EC2 인스턴스에서 직접 CI를 실행하는 대신 AWS ECS(Elastic Container Service)나 EKS(Elastic Kubernetes Service)를 사용

3) Github Action으로 쟤가 하는지 장점 : 공짜 computing 활용 + 코드 작업(pull, push 등)

(1, 3 을 뒤집으면 서로의 장단점이 됨.)

CI/CD 일을 대신해주는 것 instance로는 Github Action - 공짜 제공, Jenkins - 직접 EC2내 구축이 있다.

Action이 CD 하라고 Action에서 명령을 줄 수 있다.

CI 이관

  • 기존의 CI 환경을 새로운 환경으로 옮기는 과정 (기존에 사용하던 CI 도구나 서비스에서 다른 도구나 서비스로 변경할 때)
  • 직접 파일을 압축하여 전송 - Tar파일
  • 중앙 VCS로 간접 전송

CD 이관

  • Script로 어떤 행위를 할지 정의해야 함.

  • 구동을 위한 인스턴스

    주로 애플리케이션 또는 서비스가 실제로 실행되는 환경을 제공한다.

  • 빌드를 위한 인스턴스

    빌드를 위한 인스턴스는 소스 코드를 컴파일하고 실행 가능한 애플리케이션으로 패키징하는 과정을 수행.






🔥 아키텍처 순서

  1. 개발 프로젝트와 Github 연동
  2. AWS 계정 생성
  3. IAM 사용자 추가 (그룹 생성 및 권한 추가)
  4. EC2 서비스 인스턴스 생성
  5. EC2 인스턴스 SSH 접속
  6. Git, 자바, Jenkins 설치
  7. Jenkins 파이프라인 스크립트 작성 (Jenkins를 사용하여 CI/CD 파이프라인을 구성하고, GitHub와 연동하여 코드 변경 사항이 자동으로 빌드 및 배포되도록 설정)
  8. 빌드 및 배포

https://cyberx.tistory.com/313

Workflow

  • 한 개 이상의 job을 실행할 수 있는 자동화된 작업
  • YAML 파일로 저장되며 event에 의해 실행된다. .github/workflows 디렉토리에 YAML 파일 형식으로 workflow를 작성
  • 이 파일 내에서 AWS CLI를 사용하여 EC2 인스턴스를 생성하는 명령어를 실행하는 step을 정의

Github Action Workflow 설정

  • AWS 인증 : AWS에 접근하기 위해서는 AWS Access Key ID와 Secret Access Key가 필요.
  • 이 인증 정보는 Github 저장소의 Secrets에 안전하게 저장하고 workflow에서 사용할 수 있도록 설정한다.

Event

  • workflow 실행을 발동시키는 특정한 활동
  • 깃허브에 소스코드를 푸시하면 발생하는 push event, pull request, issue 등 깃허브에서 발생하는 대부분의 작업을 event로 정의함.

Jobs

  • 한 가지 러너안에서 실행되는 여러가지 step들의 모음
  • 각각의 step들은 일종의 shell script처럼 실행이 된다
  • step들은 순서에 따라 실행되며 step끼리 데이터들을 공유 가능
  • Job은 다른 Job에 의존 관계 가질 수 있음. 병렬 실행도 가능

Actions

  • 복잡하고 자주 반복되는 작업을 정의한 커스텀 어플리케이션
  • workflow 파일 안에서 자주 반복되는 코드를 미리 정의해 코드의 양을 줄일 수 있음


✔️ 배포 과정 총 흐름에 대한 내용.

🔗 https://bcp0109.tistory.com/363






Reference

🔗 https://velog.io/@sgwon1996/GitHub-Action으로-CICD-구축하기 (자세히 나옴.)

🔗 https://techblog.tabling.co.kr/백엔드팀에서-github-actions를-사용하는-방법-a10f03f750ba

🔗 https://velog.io/@sangwoong/CICD-GitHub-Action으로-CICD-구축하기

🔗 https://velog.io/@cjh8746/github-action-을-활용하여-CI-CD7


EC2 띄울 때는 JRE 설치가 필요하다.

JRE는 실행만 하지만 JDK는 실행과 Copile 둘 다 한다. 그래서 CI 이관 T1일 때는 JRE 설치하고 CI 이관 T2일 때는 받은 소스 코드를 컴파일 위해 빌드를 한 .class 인 JAR가 있으므로 JDK를 설치해야 한다.

Gradle을 통한 Java 구동 원리

  • Local : JAR가 아닌 다 오픈된 Exploded JAR를 사용한다. ⇒ 세밀한 디버깅 가능
    • 내 로컬에 있는 gradle, intellij 설정. 자체 gradle을 사용. 설치 필요.
    • 빌드한 .class인 Exploded JAR로 “Boot Run”하면 JRE 위에 .class 생성됨 (/build에)
    • Exploded JAR는 JAR 파일 내의 모든 내용이 폴더 구조로 압축 해제되어 있어, 파일을 직접 수정하거나 추가할 수 있다.
    • 서버에 직접 배포할 때, 압축 해제된 형태는 파일을 쉽게 교체하거나 수정할 수 있어 관리가 용이.
  • EC2 : 다운 받기엔 커서 아예 내장을 하기 때문에 ./gradlew 를 사용한다.
    • 이 자체가 실행되는 파일이다.
    • 빌드해서 JAR를 만들고 “Boot Run” 실행해서 Java를 구동하는 JRE 위에 JAR를 둔다.

문제 발생 시 대처 방법

  1. 로그를 강화해서 추론, 추적. (원칙적으로는 디버깅 불가)
  2. 예상한 동작하지 않거나, 이전 버전에 대한 설정값이 남아있다고 생각하는 경우 JAR를 뜯어 봄.

profile
일상의 인연에 감사하라. 기적은 의외로 가까운 곳에 있을지도 모른다.

0개의 댓글