본문 바로가기
MSA/Spring Microservice In Action

부록. Dockerfile과 Docker-compose를 이용한 프로젝트 빌드 및 실행

by 화트마 2022. 1. 20.

도커 환경에서 스프링 부트 프로젝트를 빌드 및 실행하는 방법을 알아보자.

 

개발 환경

개발 환경은 Spring Boot, Maven, Git, Docker입니다.

도커는 다음 사이트에서 다운로드 받을 수 있습니다.

https://www.docker.com/get-started

 

Get Started with Docker | Docker

Learn about the complete container solution provided by Docker. Find information for developers, IT operations, and business executives.

www.docker.com

윈도우에서 도커 실행 시
Docker > Settings > General 에서 Expose daemon on tcp://localhost:2375 without TLS 항목은 체크합니다.
이때 Send usage statistics 항목은 체크 해제.

 

소스코드

소스 코드 예제는 제 깃허브에서 확인하시면 됩니다.

소스 코드에 대한 자세한 설명은 제 블로그의 'Spring Microservice In Action' 카테고리 글을 참고해주세요.

https://github.com/hmg0616/msainaction-repo

 

GitHub - hmg0616/msainaction-repo

Contribute to hmg0616/msainaction-repo development by creating an account on GitHub.

github.com

 

pom.xml 분석

// licensing-service 모듈의 pom.xml 일부
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <start-class>com.hmg.licensingservice.LicensingServiceApplication</start-class>
    <docker.image.name>hmg/msa-licensing-service</docker.image.name>
    <docker.image.tag>1.0</docker.image.tag>
</properties>

<build>
    <plugins>
        <!-- We use the Resources plugin to filer Dockerfile and run.sh, it inserts actual JAR filename -->
        <!-- The final Dockerfile will be created in target/dockerfile/Dockerfile -->
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-resources</id>
                    <!-- here the phase you need -->
                    <phase>validate</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${basedir}/target/dockerfile</outputDirectory>
                        <resources>
                            <resource>
                                <directory>src/main/docker</directory>
                                <filtering>true</filtering>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>1.1.1</version>
            <configuration>
                <imageName>${docker.image.name}:${docker.image.tag}</imageName>
                <dockerDirectory>${basedir}/target/dockerfile</dockerDirectory>
                <resources>
                    <resource>
                        <targetPath>/</targetPath>
                        <directory>${project.build.directory}</directory>
                        <include>${project.build.finalName}.jar</include>
                    </resource>
                </resources>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  • <docker.image.name>, <docker.image.tag>
    : 생성될 도커이미지의 이름과 태그 지정.
  • <build>
    : 스포티파이 메이븐 플러그인으로 빌드 프로세스를 수행. 그러면 도커 이미지로 패키징됨.
    : src/main/docker 디렉터리의 콘텐츠 (Dockerfile, run.sh)를 target/dockerfile에 복사.
    : target/dockerfile 디렉터리에 정의된 Dockerfile을 실행.
    : 로컬 도커 이미지 저장소에 도커 이미지를 저장함.

Dockerfile 분석

프로비저닝할 서비스용 도커 이미지가 생성될 때마다 실행될 명령어 목록.

FROM openjdk:8-jdk-alpine
RUN  apk update && apk upgrade && apk add netcat-openbsd
RUN mkdir -p /usr/local/licensingservice
ADD  @project.build.finalName@.jar /usr/local/licensingservice/
ADD run.sh run.sh
RUN chmod +x run.sh
CMD ./run.sh
  • openjdk:8-jdk-alpine
    : 알파인 리눅스 사용해 인스턴스 배포.
    : 알파인 리눅스는 도커 이미지 빌드 시 자주 사용되는 경량 리눅스 배포판. 자바 JDK가 이미 설치되어 있음.
  • netcat-openbsd
    : nc 명령줄 도구 설치.
     :nc 명령어는 서버에 핑을 보내고 특정 포트가 온라인인지 확인하는 용도.
    : run.sh 스크립트 안의 nc 명령어로 서비스가 실행되기 전 그 서비스가 의존하는 모든 서비스(예를 들어 데이터베이스)가 실행되도록 대기.
  • ADD @project.build.finalName@.jar /usr/local/licensingservice/
    : JAR 실행 파일을 저장할 디렉터리 생성 후, 로컬 파일 시스템의 JAR를 도커 이미지에 생성된 디렉터리로 복사함
    = ADD licensing-service-0.0.1-SNAPSHOT.jar /usr/local/licensingservice/
  • CMD ./run.sh
    : CMD는 실제 컨테이너가 시작되었을 때 스크립트 혹은 명령을 실행
    : 도커 이미지가 시작될 때 대상 서비스를 실행하는 사용자 정의 스크립트

    #!/bin/sh
    
    echo "********************************************************"
    echo "Waiting for the configuration server to start on port $CONFIGSERVER_PORT"
    echo "********************************************************"
    while ! `nc -z configserver $CONFIGSERVER_PORT `; do sleep 3; done
    echo ">>>>>>>>>>>> Configuration Server has started"
    
    echo "********************************************************"
    echo "Waiting for the database server to start on port $DATABASESERVER_PORT"
    echo "********************************************************"
    while ! `nc -z database $DATABASESERVER_PORT`; do sleep 3; done
    echo ">>>>>>>>>>>> Database Server has started"
    
    echo "********************************************************"
    echo "Starting License Server with Configuration Service :  $CONFIGSERVER_URI";
    echo "********************************************************"
    java -Dspring.cloud.config.uri=$CONFIGSERVER_URI -Dspring.profiles.active=$PROFILE -jar /usr/local/licensingservice/@project.build.finalName@.jar
    : nc 명령어로 의존하는 핵심 서비스들의 포트를 확인하고 시작될 때까지 대기함
    : java -jar 명령어로 라이선싱 서비스 실행 (도커 이미지를 실제로 실행할때 올라감)
    : $CONFIGSERVER_URI는 환경 변수 값 읽어옴 (docker-compose.yml 에 설정되어있음)

 

Docker-compose.yml 분석

docker-compose.yml 에 정의된 모든 서비스를 시작하기위한 파일.

쿠버네티스 같은 서비스 오케스트레이션 도구.

도커 컴포즈에는 서비스별 환경 변수를 정의할 수도 있음.

// docker/common/docker-compose.yml
version: '2'
services:
  configserver:
    image: hmg/msa-confsvr:1.0
    ports:
       - "8888:8888"
    environment:
      ENCRYPT_KEY:       "IMSYMMETRIC"
  database:
    image: postgres:9.5
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "p0stgr@s"
      POSTGRES_DB:       "msainaction_local"
  licensingservice:
    image: hmg/msa-licensing-service:1.0
    ports:
      - "8080:8080"
    environment:
      PROFILE: "default"
      CONFIGSERVER_URI: "http://configserver:8888"
      CONFIGSERVER_PORT:   "8888"
      DATABASESERVER_PORT: "5432"
      ENCRYPT_KEY:       "IMSYMMETRIC"

도커 컴포즈는 먼저 시작할 대상의 이미지를 로컬 도커이미지에서 찾으려고 시도. 실패한다면 도커 허브에서 찾음.

ports 태그는 시작된 도커 컨테이너가 외부에 노출할 포트 번호 정의.

environment 태그는 시작된 도커 이미지에 환경 변수를 전달하는 데 사용.

 

도커 이미지 빌드 및 컨테이너 시작

1. 모듈 루트 디렉토리에서 커맨드 창에 다음 명령어를 실행해 도커 이미지를 빌드한다.

> mvn clean package docker:build

 

그러면 pom.xml에 정의했던 "도커 이미지 이름:태그" 형식의 도커 이미지가 생성된다.

2. 모듈의 루트 디렉토리에서 커맨드 창에 다음 명령어를 실행해 도커 컨테이너를 실행한다.

> docker-compose -f docker/common/docker-compose.yml up

그러면 docker-compose.yml에 정의된 모든 서비스가 하나의 도커 컨테이너에서 시작한다.

3. 실습이 끝나면 도커 컨테이너를 내린다.

> docker-compose -f docker/common/docker-compose.yml down

4. 필요 없는 컨테이너 및 이미지는 모두 삭제해준다.

> docker rmi [컨테이너 ID 또는 이미지 이름]

 


참고

만약 CMD ./run.sh 실행시 /bin/sh: run.sh: not found 에러가 발생할 경우

notepad++에서 run.sh을 파일을 열어 개행형식이 Windows(CR LF)라면 Unix(LF)로 바꿔준다,

docker-compose로 올린 이미지가 아무 에러없이 killed 메세지만 남기고 꺼질 경우

docker-compose로 한번에 많은 이미지를 컨테이너로 실행할 경우 내 가용 CPU나 메모리가 부족할 경우 이미지 파일 중 일부가 kill될 수있다.

일부 이미지를 중단시키거나, docker-compose.yml 설정에서 CPU, 메모리 제한을 걸 수 있다.

댓글