반응형

이번에 현장실습 과제가 Docker를 사용해서 지금까지 만든 프로젝트를 배포하는 것이다.

Docker를 공부해야지 해야지 하다가 결국 쓰게 되었다.

과정 자체는 크게 다를 거 같지 않으니 기록을 하며 해보려고 한다.

 

Docker 설치

당연히 Docker를 설치 해야한다.

 

우선 apt를 업데이트 해준다.

sudo apt-get update

 

그 다음엔 앞으로 사용할 프로그램들을 설치해준다.

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    gnupg \
    lsb-release

 

그리고는 Docker GPG 키를 가져온다.

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Docker Repository를 추가하고

 echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

 

이제 여기에 Docker를 설치한다

다시 apt-get을 업데이트하고 Docker를 설치해준다.

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

 

이렇게 버전을 봤을 때 잘 출력이 된다면 정상이다.

 

자바 설치

docker 다운받으면서 혹시나 하고 Java를 봤는데 설치가 안되어있다.

 

java -version만 입력을 해도 

버전들이 밑에 쭉 나온다

프로젝트에 맞게 11로 다운을 받겠다.

 

설치는 쉽다.

환경변수 설정이 어려울 뿐

 

우선 javac의 경로를 가져온다.

readlink로 실제 경로를 찾는다

sudo vi /etc/profile

profile을 열어주고

얻은 정보들을 이용하여 환경변수를 작성해준다.

 

profile을 적용시켜주고 환경변수를 출력해보면 정상작동한다.

 

MariaDB 이미지 생성

스프링 부트를 같은 도커의 MariaDB에 연결 할 것이기 때문에 MariaDB 이미지를 가져온다.

 

docker pull mariadb

이렇게만 하면 mariadb 이미지가 가져와진다.

 

이거로 컨테이너를 생성한다.

docker container run -d -p 3306:3306 -e MARIADB_ROOT_PASSWORD=<비밀번호> --name mariadb-container mariadb

 

docker ps 명령어를 입력해보면 잘 작동하는 것을 볼 수 있다.

 

여기에 들어가서 스키마와 유저를 생성해야 한다.

 

docker exec -it mariadb-container /bin/bash

이 명령어로 mariadb에 들어가서 스키마와 유저를 생성하고 오자

 

Springboot

우선 만든 프로젝트를 pull해서 가져온다.

 

대부분의 경우 application.properties가 비어있을 것이다.

거기에 이렇게 적어주면 된다.

 

여기서 또 생각해보니 maven 설치를 안했다....

maven은

apt install maven

이거로 설치할 수 있다.

 

설치가 완료되었다면 스프링 빌드 프로젝트에서

mvn clean package -DskipTests

로 jar 파일을 만들어준다.

 

target 폴더를 보면 원하는 jar 파일이 생성 된 것을 볼 수 있다.

이제 이것도 도커 위에 올리자

 

우선 Dockerfile로 이미지를 생성해준다.

 

Dockerfile은 이렇게 작성하였다.

FROM openjdk:11
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} demo-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar", "demo-0.0.1-SNAPSHOT.jar"]

 

해당 위치에서 

sudo docker build -t spring-boot-image .

이 명령어로 이미지를 생성해준다.

 

그리고 해당 이미지로 컨테이너를 만들기 위해 

version: '3'
services:
        mariadb:
                image: mariadb
                container_name: mariadb-container
                environment:
                        MARIADB_ROOT_PASSWORD: password
                ports:
                        - "????:????"
        spring-boot-app:
                image: spring-boot-image
                container_name: spring-boot-container
                restart: always
                depends_on:
                        - mariadb
                ports:
                        - "????:????"
                environment:
                        SPRING_DATASOURCE_URL: jdbc:mariadb://mariadb:3306/knudb
                        SPRING_DATASOURCE_USERNAME: user
                        SPRING_DATASOURCE_PASSWORD: password

이렇게 docker-compose.yml을 작성하고

sudo docker-compose up -d

로 컨테이너를 만들어주면 끝이다!

'현장실습' 카테고리의 다른 글

Duplicate entry error  (0) 2023.07.20
반응형

이번에 프로젝트를 하면서 File 테이블의 ID는 Long, Integer로 사용하는 것이 아닌 KeyManager라는 테이블을 참조해서 FI + (오늘의 날짜) + 인덱스 이렇게 문자열로 생성해서 넣어주게 되었다.

 

package NexaDs_Knu.practice.Data.Entity.Util;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Embeddable;
import java.io.Serializable;
import java.time.LocalDateTime;

@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
public class KeyManagerId implements Serializable {

    private String keyType;
    private String date;
}

이렇게 ID는 문자열로 타입과, 문자열로 변환된 날짜를 넣어준 KeyManagerId를 사용하고

package NexaDs_Knu.practice.Data.Entity;

import NexaDs_Knu.practice.Data.Entity.Util.KeyManagerId;
import lombok.*;

import javax.persistence.*;

@Entity
@Table(name = "KeyManager")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class KeyManagerEntity {

    @EmbeddedId
    private KeyManagerId id;


    private Long sequence;
}

이렇게 테이블을 작성하였다.

이렇게 되면 ID는 KeyType과 날짜가 되어 이 두가지가 중복된 데이터는 들어올 수 없게 되었다.

@Query("SELECT k FROM KeyManagerEntity k WHERE k.id.keyType = :keyType AND k.id.date = :date")
KeyManagerEntity findByKeyTypeAndDate(
	@RequestParam("keyType") String keyType,
    @RequestParam("date") String date);
)

이렇게 JPQL을 이용하여 KeyType과 Date에 맞는 KeyManagerEntity를 가져오고 

	public static String toPrimaryKeyId(String keyType){
        String today = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        KeyManagerEntity keyManager = keyManagerRepository.findByKeyTypeAndDate(keyType, today);
        Long sequence;
        if(keyManager == null)
        {
            keyManager = new KeyManagerEntity(new KeyManagerId(keyType, today), 1L);
            keyManagerRepository.save(keyManager);
            sequence = 1L;
        }
        else
        {
            keyManager.setSequence(keyManager.getSequence() + 1);
            sequence = keyManager.getSequence();
            keyManagerRepository.save(keyManager);
        }
        return keyType + today + String.format("%05d", sequence);
    }

이렇게 그에 따라 ID를 생성해주게 만들었다.

 

그리고 이 방법을 사용하던 도중에 에러가 발생했다.

 

자바스크립트에서 해당 방법을 사용하는 API를 반복문으로 실행하는 구문이 있었는데, 이 과정에서 

이런 에러가 발생한 것이다.

현재 toPrimaryKeyId에서 동일한 ID를 생성해주고 있는 것이었다.

 

왜 이런 일이 생겼는지 생각해보면, 스프링의 쓰레드에서 동시에 메서드에 접근하고 +1된 값을 넣어주기 전에 같은 ID를 만들어 버린 이유일 것이다.

 

어찌보면 당연한 일이었다.

이 부분을 critical section으로 만들었어야 했는데, '어차피 자바스크립트 반복문으로 들어오니 대충 순서대로 들어오겠지' 라고 생각한 나의 잘못일 것이다.

 

해결 방법은 이 부분을 atomic하게 바꿔주는 어떤 방법이든 될 수 있겠지만, 나는 가장 간단한 @Synchronized 어노테이션을 달아주었다.

이렇게만 바꿔주었더니, 더 이상 에러가 발생하지 않았다.

스프링이 쓰레드 기반으로 동작된다는 것을 다시 한 번 느낄 수 있는 에러였다.

 

 

'현장실습' 카테고리의 다른 글

Mariadb와 Springboot를 Docker에 올리기  (0) 2023.07.28

+ Recent posts