[Project] TO-DO List 만들기 (Spring Boot + Vue.js + MongoDB + Docker)

Yuri Lee·2021년 6월 9일
0

Intro

https://imasoftwareengineer.tistory.com/34?category=772561
위 글을 참조해 TO-DO List project를 만들어 보았습니다.

Development environment

  • vue.js + javascript + bootstrap
  • springboot
  • mongoDB

Architecture

어플리케이션 서버와 데이터베이스 서버가 있다. 이 두 서버는 같은 컴퓨터에 있을 수도, 다른 컴퓨터에 있을 수도 있다. 중요한 것은 서버 컴퓨터는 유저의 컴퓨터가 아니라는 것이다.

  1. 유저는 자신의 브라우저(구글크롬,사파리,등등)를 이용해 http 리퀘스트라는 것을 서버 컴퓨터로 보낸다.
  2. http 리퀘스트를 받은 어플리케이션 서버는 요청에 따라 데이터베이스 서버에 쿼리(Query)를 날려 저장된 정보를 가져오거나 내부적으로 요청을 처리한다.
  3. 이후 http response 를 다시 인터넷 브라우저에 보낸다.
  4. 인터넷 브라우저는 이 response를 해석하고 html/javascript 로직에 따라 알맞게 브라우저에 출력한다.

이렇게 유저의 브라우저의 코드(js) + 어플리케이션 서버 + 데이터베이스 서버로 나누어져 있는 어플리케이션의 아키텍처를 3-tier 아키텍쳐라고 부른다.

Features

  • REST API
  • 할일 목록 확인
  • 할일 목록 수정
  • 할일 추가하기

Screenshots

목록 확인목록 수정 및 추가

what i learned

  • Rest API
  • docker와 springboot

Error & Problem

Mongodb 관련 dependency 에러 발생

  1. 'Field required a bean of type that could not be found.' error spring restful API using mongodb
@SpringBootApplication
@EnableMongoRepositories(basePackageClasses = CustomerRepository.class)

참고: https://stackoverflow.com/questions/42907553/field-required-a-bean-of-type-that-could-not-be-found-error-spring-restful-ap

다음 어노테이션을 추가하였더니 해결되었지만, 다시 2번 에러가 발생했다.

  1. No bean named 'mongoTemplate' available. Spring Boot + MongoDB 에러 발생
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb', version: '2.5.0'

참고: https://stackoverflow.com/questions/63386079/no-bean-named-mongotemplate-available-spring-boot-mongodb, https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb/2.5.0

docker image 관련 에러 발생

  • mongo 버전을 3.2.4f로 하였더니 에러가 발생했다. 3.4로 수정하였더니 정상 작동하였다.

what i want to remember

1. docker-compose.yml

  • To Do App의 경우 일단 데이터베이스가 필요하고, backend API서비스가 필요하고, Frontend 서비스가 필요하다. 그리고 이런 웹 앱을 전부 deploy 하기 위해서는 데이터베이스, API, frontend 서버를 각각 환경설정하고 코드를 deploy해야 한다.
  • 도커의 compose는 각 컴포넌트의 Configuration과 dependency등을 yml이라는 하나의 파일에 정의하고 이 파일에 작성된대로 도커에 올려주는(deploy해 주는) 툴이다. 포트는 몇이고, 컨테이너의 이름은 뭐이고, 로그 파일은 어디에 저장하고 이런 설정들을 yml파일 안에서 명시하면 그 내용(stack이라고 부른다) 그대로 docker compose를 이용해 한번에 docker에 올릴 수 있다.
version: "3"
services:
  mongodb:
    image: mongo:3.4
    environment:
      - MONGO_DATA_DIR=/data/db
      - MONGO_LOG_DIR=/dev/null
    volumes:
      - ./data/db:/data/db
    container_name: "mongodb"
    hostname: "mongodb"
    ports:
      - 27017:27017
    command: mongod --smallfiles --logpath=/dev/null # --quiet
  app:
    image: to-do-springboot
    ports:
      - 5000:5000
    links:
      - mongodb
  • services 아래에 mongodb가 정의된 것을 확인 할 수 있다. 이 컨테이너가 어떤 이미지를 사용하고, 데이이터, 로그의 경로, 실행 커멘드, 컨테이너 이름, 포트 등을 정의한다. app 에는 만들었던 스프링 부트 앱 이름을 넣어준다.
  • links에 mongodb를 주목하자. links로 mongodb를 해 주어야 도커 컨테이너가 "아 이 컨테이너(to-do-springboot)는 옆 컨테이너인 mongodb를 사용하니까 이 컨테이너에서 오는 요청은 mongodb가 받아들여도 괜찮아."라고 알아듣는다.

(+참고 Dockerfile)

# Start with a base image containing Java runtime
FROM java:8

# Add Author info
LABEL maintainer="leyuri97@gmail.com"

# Add a volume to /tmp
VOLUME /tmp

# Make port 8080 available to the world outside this container
EXPOSE 5000

# The application's jar file
ARG JAR_FILE=build/libs/demo-0.0.1-SNAPSHOT.jar


# Add the application's jar to the container
ADD ${JAR_FILE} to-do-springboot.jar

# Run the jar file
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/to-do-springboot.jar"]
  • Dockerfile 도커가 이해 할 수 있는 파일이다.
  • 이 파일에 필요한 디펜던시 예를들어 우리와 같은 경우 어떤 자바를 사용 할 것인지, 어떤 어플리케이션(.jar)를 사용 할 것인지, 어떤 명령어로 이 도커 컨테이너를 실행시켜야 되는지에 대해 명시해야 한다.

2. build.gradle

  • 기존의 임베디드 몽고디비 관련 설정을 지우고 실제 몽고디비를 사용하기 위해 파일을 수정했다.
plugins {
    id 'org.springframework.boot' version '2.5.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'springboot-todo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    // mongo db related
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
}

test {
    useJUnitPlatform()
}

3. application.properties

server.port = 5000
spring.data.mongodb.uri= mongodb://mongodb:27017/TodoRepository
  • application.properties에서 Spring Boot가 사용할 mongo DB의 경로를 지정해준다.
  • 주의 할 점은 보통 로컬 몽고디비에 연결 할 때 mongodb://localhost:27017/xxxx이렇게 연결하는데, 도커를 이용하면 그렇게 할 수 없다는 점이다. 도커 컨테이너는 컨테이너 자체가 분리된 하나의 환경으로 인식되기 때문에 도커 컨테이너의 localhost과 스프링부트의 localhost는 같은 localhost가 아니다. 따라서 localhost를 사용하는 부분은 컨테이너 이름으로 대체 해 줘야 도커가 이를 해석해 몽고디비가 있는 도커로 연결 해 줄 수 있다.

4. Gradle clean

  • application.properties를 수정했기 때문에 재빌드를 위해 clean을 해준다.

5. docker image build

  • 도커 이미지를 빌드해준다. 성공적으로 이미지가 생성되었을 경우 다음처럼 출력된다.

  • 생성된 도커 이미지를 명령로 확인할 수 있다.

6. docker-compose

  • docker compose 전에 이미 5000 포트가 사용되는 중이면 안 되기 때문에 종료를 해줘야 한다.

  • docker-compose 를 이용해 mongo DB와 Spring boot를 도커에 올린다.

  • docker ps로 잘 실행되고 있는지 확인한다.

  • (+) docker desktop 화면을 보면 springboot-todo 를 확인할 수 있다.

7. npm run dev

  • react 쪽으로 넘어가 npm run dev 스크립트를 사용하여 서버를 실행한다.

docker 컨테이너 종료 후

  • docker-compose 실행한 terminal에서 ctrl+C로 종료할 수 있다.
  • 그 후 다시 docker-compose를 하면 이전에 만들었던 todo item들이 삭제되지 않고 출력된다.
  • 이전엔 임베디드 mongoDB를 이용했기 때문에 서버 종료 후엔 item들이 다 삭제된다.

End

해당 튜토리얼을 따라하면서 예상치 못한 에러들을 만났다. 그럼에도 구글링을 하면서 에러를 해결하려고 했고, docker 컨테이너를 올리는 것 까지 성공할 수 있었다. 👋

사실 docker 는 학부 때 한번 다뤄보긴 했으나 몇년 뒤 다시 해보려니 기억이 나질 않았다.. Dockerfile에 정의한 내용으로 도커 이미지를 빌드하고, docker-compose.yml 를 통해 도커에 deploy 된다는 것. 기억하자!!!!

번외이긴 하지만.. 도커의 포트 번호를 명시해주는 부분이 헷갈린다. 이 부분은 다시 한번 꼭 살펴봐야 될 것 같다.

많은 기능을 담고 있는 프로젝트는 아니였지만, 개념을 상기시키는 좋은 토이 프로젝트였다. 😊

git

https://github.com/leyuri/todo-frontend
https://github.com/leyuri/todo-backend


https://stackoverflow.com/questions/48280589/mongo-is-not-able-to-reach-from-docker-container
https://stackoverflow.com/questions/49139704/spring-boot-mongo-mongosocketexception
https://imasoftwareengineer.tistory.com/34?category=772561
https://chaelin1211.github.io/study/2021/02/19/todo-project-02.html
https://chaelin1211.github.io/study/2021/03/12/springboot-error-01.html
https://imasoftwareengineer.tistory.com/40

profile
Step by step goes a long way ✨

0개의 댓글