스프링 부트 애플리케이션을 Docker image로 빌드해서 컨테이너에 올리는 작업을 진행해 보겠다.

 

필요사항

  • JDK 1.8 later
  • Maven 3.2 이상
  • STS
  • Docker

 

Pom.xml 수정을 먼저 진행해야한다.

  • wedul 이라는 이름의 jar 파일이 생성된다.
  • docker에서 실행하기 위한 Maven 설정이 들어있는 jar file이 만들어 진다.
  • 만약 image prefix 값을 별도로 지정하지 않으면 artifact id가 명시된다.
<properties>
   <docker.image.prefix>wedul</docker.image.prefix>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>dockerfile-maven-plugin</artifactId>
            <version>1.3.6</version>
            <configuration>
                <repository>${docker.image.prefix}/${project.artifactId}</repository>
                <buildArgs>
                    <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                </buildArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

 

그리고 프로젝트 Root에 Dockerfile을 위치시켜야 한다. 

FROM java:8
VOLUME /tmp
ADD /target/wedulpos-0.0.1-SNAPSHOT.jar wedulpos.jar
ENTRYPOINT ["java","-jar","wedulpos.jar"]

DockerFile 옵션 설명 (출처 : https://www.callicoder.com/spring-boot-docker-example/)

VOLUME 

볼륨은 호스트 OS에서 컨테이너에 의해 생성 된 데이터를 유지하고 호스트 OS에서 컨테이너로 디렉토리를 공유하는 메커니즘입니다.

VOLUME 명령은 컨테이너에 지정된 경로로 마운트 포인트를 작성합니다. 컨테이너를 실행할 때 지정된 마운트 지점이 매핑 될 Hot OS의 디렉토리를 지정할 수 있습니다. 그런 다음, 컨테이너가 마운트 된 경로에 쓰는 것이 호스트 OS의 매핑 된 디렉토리에 기록됩니다. 볼륨의 가장 일반적인 사용 사례 중 하나는 컨테이너에 의해 생성 된 로그 파일을 호스트 OS에 저장하는 것입니다.

예를 들어, 응용 프로그램이 로그 파일을 /var/log/app.log 위치에 기록한다고 가정 해 봅시다. Dockerfile에 / var / log 경로로 VOLUME을 마운트 한 다음 컨테이너를 실행하는 동안이 마운트 지점이 매핑 될 호스트 OS의 디렉토리를 지정할 수 있습니다. 그런 다음 호스트 OS의 매핑 된 디렉토리에서 로그에 액세스 할 수 있습니다.

위의 Dockerfile에서 / tmp 경로를 사용하여 마운트 지점을 만들었습니다. 이것이 스프링 부트 응용 프로그램이 Tomcat에 대한 작업 디렉토리를 기본적으로 만드는 위치이기 때문입니다. 이 스프링 부트 응용 프로그램에는 바람둥이 디렉토리에 관심이 있기 때문에 필수는 아니지만. 그러나 Tomcat 액세스 로그와 같은 항목을 저장하려는 경우 VOLUMES는 매우 유용합니다.

 

ADD

ADD 명령은 새 파일과 디렉토리를 고정 이미지에 복사하는 데 사용됩니다.

 

ENTRYPOINT

응용 프로그램이 컨테이너 내부에서 실행되는 방법을 구성하는 곳입니다. 

 

그렇게 설정을 마치고 명령어를 통해 docker에서 사용할 수 있는 이미지 파일로 빌드를 진행한다.

./mvnw install dockerfile:build

설정을 정상적으로 하고 빌드가 진행이 완료되면 BUILD SUCCESS가 보일 것이다.

Docker image ls 명령어를 통해 지금 설치가 완료된 이미지 파일도 확인할 수 있다.

 

 


Feign는 넷플릭스에서 개발된 HTTP 클라이언트다.

Feign은 HTTP API 클라이언트를 간단하게 제공한다. Feign을 사용하기 위해서는 인터페이스를 선언하고, 어노테이션화 하면 이를 런타임에서 실제 구현을 제공된다.

Feign 라이브러리 추가
- feign-okhttp는 request를 만들기 위해서 내부적으로 Square OkHttp 클라이언트를 사용하기 위해 사용
- feign-gson은 JSON 처리기로서 Google Gson을 사용하기 위해 로드
- feign-slf4j는 request들을 로깅하기 위해서 라이브러리 사용



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>9.3.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
    <version>9.3.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-slf4j</artifactId>
    <version>9.3.1</version>
</dependency>
cs





Feign 인터페이스 추가
- Feign 클라이언트는 텍스트 기반 HTPP API이다. 그렇기 때문에 파일 다운로드나 업로드를 위한 binary data는 다룰 수 없다.
- 인터페이스에 메소드에 @ReqeustLine에 요청 method와 url을 기재해 준다.
- RequestLine에 기재된 사용 방법을 보면 다음과 같다.



1
2
@RequestLine("GET /servers/{serverId}?count={count}")
void get(@Param("serverId") String serverId, @Param("count") int count);
cs



아래 Wedulpos에서 사용하는 API를 호출하는 인터페이스를 만들었다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.wedul.common.util.rest;
 
import feign.RequestLine;
 
/**
 * Http Request Client
 * 
 * @author wedul
 *
 */
public interface RestClientI {
 
    @RequestLine("POST /password/find")
    String findPassword();
    
}
cs





Feign Client 호출
- 인터페이스 기반의 클리이언트를 구성하기 위해서 Feign.builder()을 사용할 수 있다.
- JSON/XML 등 여러 encoder와 decoder를 사용 할 수 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.wedul.wedulpos.user.test;
 
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import com.wedul.common.util.rest.RestClientI;
import com.wedul.wedulpos.user.CommonTestConfiguration;
 
import feign.Feign;
import feign.Logger;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {CommonTestConfiguration.class})
public class FeignTest {
    
    RestClientI restClientI;
    
    @Before
    public void setUp() throws Exception {
        restClientI = Feign.builder()
                  .client(new OkHttpClient())
                  .encoder(new GsonEncoder())
                  .decoder(new GsonDecoder())
                  .logger(new Slf4jLogger(RestClientI.class))
                  .logLevel(Logger.Level.BASIC)
                  .target(RestClientI.class"http://localhost:8080/wedulpos/user");
    }
    
    @Test
    public void feignTest() {
        System.out.println("Feign test result : " + restClientI.findPassword());
    }
 
}
cs




https 도 가능하다
자세한 예제는 https://github.com/OpenFeign/feign 참조.








  1. hojak99 2018.07.26 17:43

    감사합니다


스프링에는 데이터를 
캐시로 보관할 수 있는 캐시 기능을 제공한다. 그 중 대표적으로 사용되는 Ehcache(ehcache-spring-annotation)에 대해 알아보자.



이를 사용하는 가장 대표적인 이유는 다음과 같다.

1. 꾸준하게 동일한 데이터 
2. 조회하여 데이터를 가지고 오는데 비용이 많이 소모되는 경우




[설정방법]

pom.xml

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>
cs



applicationContext.xml 수정


<import resource="applicationContext-cache.xml" />



applicationContext-cache.xml 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
 
<ehcache:annotation-driven />
 
<ehcache:config cache-manager="cacheManager">
<ehcache:evict-expired-elements interval="300" />
</ehcache:config>
 
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="/WEB-INF/cache/ehcache.xml" />
</bean>
 
</beans>
cs




Ehcache 설정 파일 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
maxBytesLocalHeap="32M" maxBytesLocalOffHeap="128M"
maxBytesLocalDisk="0M" updateCheck="false">
 
<cache
name="WedulCache"
maxElementsInMemory="100"
eternal="false"
overflowToDisk="false"
timeToLiveSeconds="30" />
 
</ehcache>
cs




- maxElementsInMemory : 한번에 최대 몇개의 엘리먼트 보관 가능한지 여부
- overflowToDisk : 캐시를 디스크에 쓰기.


캐시가 필요한 부분에 캐시적용



1
2
3
4
5
6
7
8
9
@Cacheable(value="findMemberCache", key="#name")
public Student findByNameCache(String name) { 
  return new Student(201014448"cjung@gmail.com", name);
}
 
@CacheEvict(value = "findMemberCache", key="#name")
public void refresh(String name) { 
  logger.info(name + "의 Cache Clear!");
}
cs





value는 encache.xml에 정의한 캐시 이름이고 key는 해당 캐시의 고유 키이다.
위의 구조는 name별로 캐시가 쌓이는 구조이다.

@CacheEvict는 캐시를 초기화하는 것이다.

※ 비고
ehcache.xml 설정 값.
http://www.ehcache.org/ehcache.xml





+ Recent posts