DevOps

AWS 컨테이너 서비스 3-Tier w/테라폼 & CI/CD 구성하기 - (2) 데모 애플리케이션 개발

yingtao 2025. 6. 2. 21:08

본격적인 아키텍쳐 구축에 앞서 간단한 방문자 기록 애플리케이션을 개발할 것이다.

데모 애플리케이션 구조 개요

  • 프론트엔드 : React (정적 페이지) → S3 + CloudFront에 배포
  • 백엔드 : Springboot (REST API) → ECS / EKS 에 배포

 

백엔드 (Springboot) 애플리케이션 개발

  • API
    • /health : 헬스 체크
    • /api/visit : POST 요청으로 이름 + 방문 시간 저장
    • /api/visits : GET 요청으로 전체 방문기록 반환

Spring Initializer 설정하기

https://start.spring.io/

현재 로컬 환경에 Java 21 버전이 설치되어있어 21버전으로 맞춰서 생성해줬다.

코드 구조

  • build.gradle
dependencies {

	...

    // JPA
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // H2 DB (개발 및 테스트용 인메모리 DB)
    runtimeOnly 'com.h2database:h2'
}

 

  • Entity
    DB 테이블과 매핑되는 클래스로 실제로 저장되는 데이터의 구조를 정의한다. 
package com.example.demo_backend.domain;

import jakarta.persistence.*;
import java.time.LocalDateTime;

@Entity
public class Visit {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private LocalDateTime visitTime;

    public Visit() {}

    public Visit(String name, LocalDateTime visitTime) {
        this.name = name;
        this.visitTime = visitTime;
    }

    // Getter, Setter 생략 or Lombok(@Getter @Setter) 사용 가능
}
  • Visit 객체가 DB의 visit 테이블과 매핑된다.
  • 각 필드(id, name, visitTime)은 DB의 컬럼과 매칭된다.

 

  • DTO
    Entity를 직접 노출하지 않고 중간에서 데이터를 담아 클라이언트와 데이터를 주고받는다.
package com.example.demo_backend.dto;

public class VisitDTO {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • 사용자가 방문 기록을 남길 때 이름만 전달하면 되므로 name 컬럼만 존재. (visitTime은 사용자가 직접 넣지 x)

 

  • Repository
    Entity에 대한 DB 접근 담당
package com.example.demo_backend.repository;

import com.example.demo_backend.domain.Visit;
import org.springframework.data.jpa.repository.JpaRepository;

public interface VisitRepository extends JpaRepository<Visit, Long> {
}

 

  • Controller
    HTTP 요청 받아 처리하는 API 진입 지점
package com.example.demo_backend.controller;

import com.example.demo_backend.domain.Visit;
import com.example.demo_backend.dto.VisitDTO;
import com.example.demo_backend.repository.VisitRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@RestController
@RequestMapping("/api")
public class VisitController {

    @Autowired
    private VisitRepository visitRepo;

    @PostMapping("/visit")
    public ResponseEntity<?> addVisit(@RequestBody VisitDTO dto) {
        visitRepo.save(new Visit(dto.getName(), LocalDateTime.now()));
        return ResponseEntity.ok().build();
    }

    @GetMapping("/visits")
    public List<Visit> getVisits() {
        return visitRepo.findAll();
    }
}

 

배포 테스트 

로컬에서 애플리케이션이 정상적으로 동작하는지 확인한 후, docker 이미지로 패키징하며 테스트를 진행한다.

  • 로컬 docker container 환경에서 jar 실행 테스트

Dockerfile 구성 (최상위 디렉토리에 위치해준다.)

# Build
FROM gradle:8.5-jdk21 AS builder

WORKDIR /app

# 전체 프로젝트 복사
COPY . .

# JAR 빌드
RUN gradle build --no-daemon

# Run
FROM openjdk:21

WORKDIR /app

# 위 단계에서 만든 JAR 복사
COPY --from=builder /app/build/libs/demo-backend-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080
EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

실행

docker build -t demo-backend:full .

docker run -d -p 8080:8080 demo-backend:full

테스트

방문 가정 curl 테스트
http://localhost:8080/api/visits 에서 확인 가능

 

다음에는 AWS 인프라 구성과 ECS 를 Terraform으로 구성한 뒤, ECS 환경에서 테스트를 진행할 예정이다.
DB역시 테스트용 H2가 아닌 실제 RDS와 연결할 예정이다.