개요.

스프링부트 2.3 버전이 릴리즈되면서 부트에서 도커 이미지를 만들 수 있도록 지원한다!
본 포스팅은 부트로 도커이미지를 빌드하는 법을 설명한다. (인텔리제이 기준)
도커의 기본적인 이해는 다른 블로그를 참고하길 바란다.

프로젝트 생성

간단하게 Spring Web, Spring Boot DevTools 을 의존성에 추가시키고 프로젝트를 만들자.

Spring boot DevTools

간단히 말하자면 classpath에 속해있는 파일들의 변경사항이 생기면 자동으로 어플리케이션을 재시작한다. 재시작버튼이 아니라 build버튼을 눌러도 같은 효과를 기대할 수 있다.

코드작성

SampleController.class

간단한 controller 클래스를 만들자!

package kr.gracelove.builddockerimagedemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by GraceLove on 2020/06/02.
 * Contact : govlmo91@gmail.com
 */
@RestController
public class SampleController {

    @GetMapping("/")
    public String hello() {
        return "Hello World";
    }
}

실행

GET 방식으로 '/' 로 들어온다면 응답본문에 "Hello World" 를 반환하는 간단한 컨트롤러다. 의도한대로 잘 작동하는 지 애플리케이션을 시동하고, '/'로 접속해보자.

의도한 대로 동작하는 걸 볼 수 있다.

DevTools를 이용한 재시작

hello() 메서드가 return 하는 문자열을 변경한 뒤 build 버튼을 눌러보자. 그 다음 다시 '/' 경로로 접속해보자.

변경 전 return 하는 문자열 : "Hello World"
변경 후 return 하는 문자열 : "Hello GraceLove"

변경 후 다시 build를 한 뒤 '/'로 접속해보자.

어플리케이션을 재시작하지 않아도 변경사항이 적용됨을 확인할 수 있다!

도커이미지 빌드하기.

어플리케이션을 중지시킨 뒤, 터미널에서 다음과 같은 명령어를 내리자!
./mvnw spring-boot:build-image

만약 도커이미지를 처음 build 하는 거라면 시간이 굉장히 오래걸리니 인내심을 갖자.

 

빌드가 완료됐다!

도커 컨테이너 실행시키기.

다음과 같은 명령어를 입력하자!

docker run --tty --publish 8080:8080 <위에서 build된 이미지 이름>
docker run --tty --publish 8080:8080 build-docker-image-demo:0.0.1-SNAPSHOT

옵션은 다른 블로그나 책을 참고하자.

실행이 됐다. 다시 '/' 로 접속해보자 브라우저에 Hello GraceLove 가 표시되는 걸 볼 수 있다.

도커로 실행시킨 어플리케이션 remote로 접속하고 DevTools로 재시작해보기.

먼저 Run/Debug Configurations 로 들어가자. Add New Configuration 으로 Application을 추가한다.

추가된 Application에서는 다음과 같이 설정한다.

Main class :
org.springframework.boot.devtools.RemoteSpringApplication

Program arguments :
http://localhost:8080

완료됐으면 추가한 Remote Application을 실행시킨 후 '/'로 접속해보자. 우리가 기대한 대로 잘 동작하는 것을 볼 수 있다.

DevTools 사용해보기

지금 상황에서는 hello() 메서드의 return 값을 수정한 뒤 build해도 재시작이 되지 않는다. 원격 어플리케이션에 devtools 를 사용하기 위해선 다음과 같은 작업이 필요하다.

pom.xml

...
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludeDevtools>false</excludeDevtools>
                </configuration>
            </plugin>
        </plugins>
    </build>

실행.

pom.xml 을 위와 같이 설정한 뒤 다시 도커 이미지를 빌드하자. ./mvnw spring-boot:build-image
그 다음 도커를 실행시킨 뒤, docker run --tty --publish 8080:8080 build-docker-image-demo:0.0.1-SNAPSHOT
Remote Application을 실행시켜보자.

실행시킨뒤 '/'으로 가서 Hello GraceLove가 브라우저에 표시되는 지 보고, hello()메서드의 return 문자열을 'Hello World' 로 수정한 뒤 build해보자.
다음과 같은 로그가 뜬다.

다시 '/' 로 가보면 우리가 기대했던 'Hello World'가 표시되는 걸 볼 수 있다.
이로써 Remote Application 에도 DevTools가 잘 붙는 걸 알 수 있다.

YAML 파일 변수에 매핑하기. (@Value, @ConfigurationProperties)

@Value

application.yml

property:
  test:
    name: property depth test
propertyTest: test
propertyTestList: a,b,c

ValueTest.class

@SpringBootTest
public class AutoConfigurationApplicationTests {

    @Value("${property.test.name}")
    private String propertyTestName;

    @Value("${propertyTest}")
    private String propertyTest;

    @Value("${noKey:default value}")
    private String defaultValue;

    @Value("${propertyTestList}")
    private String[] propertyTestArray;

    @Value("#{'${propertyTestList}'.split(',')}")
    private List<String> propertyTestList;

    @Test
    void testValue() {
        assertEquals("property depth test", propertyTestName);
        assertEquals("test", propertyTest);
        assertEquals("default value", defaultValue);
        assertArrayEquals(new String[]{"a","b","c"}, propertyTestArray);
        assertEquals(List.of("a","b","c"), propertyTestList);
    }
}

@ConfigurationProperties

application.yml

car:
  list:
    - name: Porsche911
      color: red
    - name: K5
      color: black

Car.class

public class Car {

    private String name;
    private String color;

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                '}';
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

CarProperty.class

@Component
@ConfigurationProperties("car")
public class CarProperty {

    private List<Car> list;

    public List<Car> getList() {
        return list;
    }

    public void setList(List<Car> list) {
        this.list = list;
    }
}
  • Car.class, CarProperty.classSetter메서드 또는 Constructor가 필요하다.
  • 바인딩할 변수의 이름과 yaml 파일에 있는 이름이 매치해야한다. (케밥표기법, 소문자 가능)
  • @Value와는 다르게 SpEl은 사용이 불가하다.
  • @Component로 스프링이 관리하게 해야한다
  1. 먼저 인증서를 만들자.

    • 터미널에서 다음과 같이 입력한다.
      • keytool -genkey -alias gracelove -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000
  2. application.properties 에 다음과 같이 적절한 값을 넣어준다.

  3. 컨트롤러를 만들자.

  4. 터미널에서 curl 로 요청을 보내보자

    • curl -I -k --url https://localhost:8443/hello
    • 리스폰스라인을 보면 HTTP2로 통신한 것을 볼 수 있다

 

참고소스. https://github.com/gracelove91/springboot-with-whiteship/tree/453045f3aa4496822181375fa208b244d4321a9c

Resource

  • 리소스를 읽어오는 기능을 제공하는 인터페이스.
  • ApplicationContext extends ResourceLoader
@Component
@RequiredArgsConstructor
public class AppRunner implements ApplicationRunner {

    private final ResourceLoader resourceLoader;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        Resource resource = resourceLoader.getResource("classpath:test.txt");
        System.out.println("resource = " + resource.exists());

        System.out.println("=======Files.readString()==================");
        System.out.println(Files.readString(Path.of(resource.getURI())));
        System.out.println("===========================================");


        BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()));
        System.out.println(br.readLine());
    }
  • resources 폴더 밑에 "test.txt"파일이 위치한다.

+ Recent posts