반응형

Pivotal 에서 개최한 Cloud-Native Day 세미나에 다녀왔다.

 

https://connect.pivotal.io/CND_Seoul_2019.html

 

Pivotal Cloud Native Day 2019 Seoul

Pivotal combines our cloud-native platform, developer tools, and unique methodology to help the world’s largest companies transform the way they build and run their most important applications. Our technology is used by Global 2000 companies to achieve str

connect.pivotal.io

요즘 관심을 갖고 있는 주제가 Cloud, Kubernetes, Microservice 였는데 마침 Pivotal 에서 Microservice  관련 해서 세미나를 해서 아주 기쁜 마음으로 다녀왔다.

클라우드 네이티브 IT를 위한 4가지 요소와 상관관계
- DevOps, CI/CD, Container, MSA

클라우드 네이티브로 가기 위한 4가지 요소로 DevOps, CI/CD, Container, MSA 를 꼽았다. 각각의 요소들은 다음과 같은 의미를 가지고 있다.

DevOps : 작은 단위의 조직. (보통 Two Pizza team 이라고 많이들 한다.)

CI/CD : 자동화, 시각화, 프로세스의 단순화

MSA : 컴포넌트 단위의 모듈화

Container : MSA를 활용할 수 있는 infra적 요소

 

현재 모놀리스 환경의 어플리케이션들이 클라우드 네이티브로 가기 위해서는 단순히 MSA 적용한다고 해서 되는것은 아니다. 그것을 운영, 개발하는 조직부터 시작해서 모든것이 그것을 잘 활용할 수 있도록 변해가야 가능한 일이다.

 

그리고 왼쪽 사진의 표에 보면 MSA 라면 한가닥 하는 회사들이 나와있다. 그 회사들의 어플리케이션 배포 주기, 배포 준비 시간을 보면 정말 놀랄만 하다. 대부분 실시간으로 사용자에게 서비스를 하는 회사들인대에도 불구하고 일단위로 배포 횟수가 상상을 초월한다. 우리 회사에서는 부끄럽지만 상상도 할수 없는 수치이다. 그런데 그보다 더 중요한 부분이 아래 빨간색으로 써있다. 배포 횟수가 중요한게 아니라 배포가 필요할때 즉시 배포 할수 있는 환경이 중요한 것이다. 여기서 말하는 배포는 무중단 배포를 의미한다. 배포때문에 사용자가 서비스를 사용하지 못하는 그런 배포를 의미하는게 아니다. (그런거 직접 경험 하면 뿌듯할것 같다... )


마이크로서비스 어떻게 디자인할 것인가.
- Pivotal AppTX

MSA를 할때 항상 고민이 되는게 Bounded Context 이다. 대체 어디까지를 하나의 서비스로 볼것인가. 

Pivotal 에서는 다음과 같은 절차로 진행을 한다고 한다. 

1. 목표설정

2. Event Storm

Event Storming 을 통해서 필요한 Event 들을 도출한다. 이건 개발자만 하는게 아니다. 개발자, 설계자, 운영자(현업?) 등이 모여서 실제 모습을 도출해 낸다. 여기에는 프로그래밍적 요소는 없다. 그리고 이것을 통해 서비스의Bounded Context를 설정한다. 

 

3. Thin Slice

Event Storming 을 통해 도출된 내용중 하나의 서비스를 선택한다. 

 

4. Boris

Boris Diagram 을 만든다. 서비스의 흐름에서 발생하는 이벤트 들을 도식화 한것이다. 이걸 함으로써 하나의 서비스에 대한 전체적인 아키택처를 확인할 수 있다. 

(화면에서 보면 포스트잇과 종이를 이용해서 했는데 툴을 사용하지 않는 이유는 툴을 사용하면 툴로 내용을 적는 사람이 말이 많아지며 다른 사람의 참여가 낮아지기 때문이라고 한다. 그리고 종이와 포스트잇을 가지고 하는것 보다 효율적인 툴을 아직까지는 보지 못했다고 한다. Event Storming 때에도 포스트잇과 종이를 이용한다고 한다. )

 

5. Snap-E

이 단계 에서는 각 단위의 api 를 정의하고 데이터 처리 및 로직을 정의한다.

 

6. 테스트 완료 및 코드 생성

7. 재사용 가능한 패턴 정리

 

이렇게 사이클이 마무리 되면 아래와 같은 흐림이 나오게 된다. 

오늘 들은 내용들 중에서 가장 기억에 남는 세션이었다. 요즘 회사에서 개발을 하면 그냥 화면 단위로 하나씩 쪼개서 맡아서 개발한다. 저렇게 서비스에 대한 내용을 다같이 모여서 그려본다든지 해본적은 거의 없었던것 같다. 단지 말로 전달 받고 그때그때 물어가면서 개발을 했다. 그런데 생각해보면 안한거지 못할 정도의 상황은 아닌것 같다. 그리고 이렇게 포스트잇으로 그려보면서 하면 좀더 재미있고 구체적인 설계가 가능하지 않을까 생각이 들었다.


마이크로서비스 어떻게 구현할 것인가.

구현의 측면에는 다른것도 다 쉽지는 않지만 특히 Database, Transaction 부분이 어렵다고 한다. 그래서 Cache, Event Sourcing 등을 사용해서 어려운 부분들을 해결한다고 한다. 


클라우드 네이티브 플랫폼의 미래
- Kubernetes 기반의 PCF 로드맵

PCF가 지향하려는 방향이 멀티 클라우드에서 벤더에 관계 없이 서비스를 사용할수 있게 해주고 개발자는 서비스 개발에만 집중할수 있도록 만들어주는 것이다. 그걸 위해서 Istio 와 Envoy 를 사용하고 있다고 한다. 이 두개는 전에 Google Cloud 세미나에서도 자주 언급되었던 건데 내용을 좀더 자세하게 살펴봐야겠다.

또 추가적으로 빌드팩에 대해서도 설명을 했다.

보통 도커 이미지를 만들려면 사용자가 필요한 라이브러리들을 Dockerfile에 정의하고 해야 하는데 빌드팩은 그런게 필요 없었다.

개발자가 서비스를 개발해서 PKS에 cf push 를 통해서 올리면 자동으로 필요한 라이브러리들을 찾아서 이미지를 만들어준다. 그리고 도커 이미지의 특정 레이어를 rebase 해서 교체를 할수 있다. (이게 좀 신기했다.)


Pivotal Concourse 를 활용한 CI/CD pipeline automated build-up & Workflow management solution 소개

CI/CD 툴로 Jenkins가 아닌 Concourse를 소개하는 세션이었다. 

Jenkins 가 UI 를 통해서 쉽게 Build pipeline을 만들 수 있는데 오히려 그 부분이 약점이 라고 한다. Concourse  는 특정 파이프라인을 만들고 지우고 또 새로 생성하는 모든 부분들을 yaml을 파일에 정의해서 자동으로 실행을 할수 있다. 그런데 yaml 파일 작성이 쉽지는 않다고 들었던것 같다. ^^;


숨겨진 마이크로서비스

캐시, 메세지 큐에 대한 내용이 많았다. 그리고 MSA를 위한 여러가지 아키텍처에 대한 설명도 있었는데 역시 마지막 시간은 집중력이 떨어졌다. ^^;; 특히 Kafka 를 로그를 위한 장치가 아닌 다른 용도로 응용해서 사용할수도 있는데 꼭 알아두라고 한다. 전에 개인 발표 때문에 Kafka 쓰다가 사리 나올뻔 했는데 이번 기회에 다시 한번 보는것도 좋을것 같다. 


 

언제나 그랬듯이 세미나를 들으면 공부 뽐뿌가 오게 된다. 일단 적어두고 차근차근 알아보자.!!!

Kafka, EvCache, Istio, Envoy

 

그리고 올해도 역시 spring one 행사가 열린다. 얼리버드는 할인을 해준다는데...정말 가고싶다. ㅠㅠ 언제쯤 한번 가볼수 있으려나...

 

728x90
반응형
반응형

컨트롤러를 만들어서 Testcase 를 작성한 후에 성공할거라 믿고 돌려봤는데 IllegalArgumentException 이 발생했다.

컨트롤러 코드와 테스트 케이스 코드는 각각 다음과 같다.


UserController.java

1
2
3
4
5
6
@GetMapping(value = "/users/{email}")
public UserDto.Res getUser(@PathVariable @Valid final String email){
    Optional<Users> users = userService.findByEmailValue(email);
 
    return new UserDto.Res(users.get());
}
cs


UserControllerTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Before
public void setUp(){
    users = Users.builder()
            .email(Email.builder().value("test@test.com").build())
            .firstName("TEST")
            .lastName("KIM")
            .password("password")
            .build();
}
 
@Test
public void getUserTest() throws Exception {
 
    given(this.userController.getUser("test@test.com")).willReturn(new UserDto.Res(this.users));
 
    ResultActions resultActions = this.mockMvc.perform(
            get("/users/{email}""test@test.com"))
            .andDo(print());
 
    resultActions
            .andExpect(jsonPath("firstName").value("TEST"))
            .andExpect(jsonPath("lastName").value("KIM"))
            .andExpect(MockMvcResultMatchers.status().isOk());
}
cs


Exception

Caused by: java.lang.IllegalArgumentException: Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.


대체 뭐지??? 맞게 parameter 도 넘겼는데 왜 못찾는거지....



Spring Document 를 보니 다음과 같은 내용을 찾을수 있었다.

The matching of method parameter names to URI Template variable names can only be done if your code is compiled with debugging enabled. If you do have not debugging enabled, you must specify the name of the URI Template variable name to bind to in the @PathVariable annotation.

<출처 : https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch18s02.html >


컴파일 할때 debugging enabled 가 되어야 동작을 하는데 그렇지 않을 경우에는 반드시 @PathVariable 사용시 name 에 값을 줘야 한다고 되어있다.


그럼 컴파일 할때 debugging enabled 는 뭔가?? -_-;;

java 소스를 컴파일할때 사용되는 javac 명령어를 찾아보면 다음과 같은 옵션이 있다. 컴파일시에 -g 옵션을 사용할 경우 로컬 지역변수(local variables) 를 포함한 debugging information 을 생성하고 디폴트로는 라인 넘버와 소스파일 정보만 생성된다고 써있다.


-g
Generate all debugging information, including local variables. By default, only line number and source file information is generated.
-g:none
Do not generate any debugging information.
-g:{keyword list}
Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are:
source
Source file debugging information
lines
Line number debugging information
vars
Local variable debugging information

<출처 : https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html>



그럼 간단한 자바 클래스를 컴파일 해서 확인해보자.


1
2
3
4
5
6
public class Test {
    public static void main (String[] args) {
        String name = "test";
        System.out.println(name);
    }
}
cs

javac Test.java (옵션 없이 할경우)

1
2
3
4
5
6
7
8
9
10
11
12
13
# javap -l Test                                 
Compiled from "Test.java"                       
public class Test {                             
  public Test();                                
    LineNumberTable:                            
      line 4: 0                                 
                                                
  public static void main(java.lang.String[]);  
    LineNumberTable:                            
      line 6: 0                                 
      line 7: 3                                 
      line 8: 10                                
}                                               
cs


javac -g Test.java (-g 옵션을 붙여서 할경우)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# javap -l Test
Compiled from "Test.java"
public class Test {
  public Test();
    LineNumberTable:
      line 40
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   LTest;
 
  public static void main(java.lang.String[]);
    LineNumberTable:
      line 60
      line 73
      line 810
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
          3       8     1  name   Ljava/lang/String;
}
cs


각각의 경우를 javap 명령어로 확인해 보았다. (javap 명령어는 컴파일된 class 파일을 역 어셈블 해주는 명령어 있다. -l 옵션을 붙이면 로컬변수 테이블까지 보여준다.)


첫번째에서는 기본적으로 라인만 보이는데 두번째에서는 로컬 변수까지 다 보여준다. 


결론적으로 맨 처음 Testcase 에서 발생했던 문제는 UserController.java 를 컴파일 했을때 -g 옵션이 안들어가서 컴파일 후에 @PathVariable 에 있는 변수를 못찾아서 발생한 문제였다. 이게 IntelliJ 에서 따로 compile 옵션설정을 해야 할지는 잘 모르겠는데 나는 @PathVariable 에 name 을 명시해주는 방법으로 해결을 했다.


참고자료

https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-path-variable.html

https://objectpartners.com/2010/08/12/spring-pathvariable-head-slapper/

https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/parameter-name-discoverer.html

https://stackoverflow.com/questions/5746894/what-does-the-javac-debugging-information-option-gvars-do

728x90
반응형
반응형

요즘에 한참 클라우드 관련 내용들을 공부하고 도커, 쿠버네티스 에 대한 내용을 보다보니 마이크로 서비스에 대한 내용들을 자주 접하게 되었다. 컨테이너를 사용한 환경에서 어플리케이션을 배포하고 관리 하려면 아무래도 덩치가 큰것 보다는 좀더 작게 모듈화 해서 배포 하는것이 나을 것이다. 어플리케이션의 크기가 작아진다는 것은 간단히 생각해봐도 배포시간이 줄어들고 그렇게 되면 다운 타임 또한 줄어들게 된다. (물론 배포 전략에 따라서 이런 부분들은 없도록 하는게 맞다.) 그래서 나 또한 마이크로 서비스에 대해서 다시 관심을 갖게 되었고 이것저것 책을 찾아보고 읽어보고 있었다. 전부터 관심이 있어서 한번 읽어봐야겠다고 생각은 하고 있었는데 길벗 개발자 리뷰어에 선정되어서 이렇게 책을 접할수 있게 되었다. (베타리더때도 신청을 했었지만 그때에는 선정되지는 못했었다. ^^;)



목차는 아래와 같이 구성이 되어있다.


1장 스프링, 클라우드와 만나다.

2장 스프링 부트로 마이크로 서비스 구축

3장 스프링 클라우드 컨피그 서버로 구성 관리

4장 서비스 디스커버리

5장 나쁜 상황에 대비한 스프링 클라우드와 넷플릭스 히스트릭스의 클라이언트 회복성 패턴

6장 스프링 클라우드와 주울로 서비스 라우팅

7장 마이크로서비스의 보안

8장 스프링 클라우드 스트림을 사용한 이벤트 기반 아키텍처

9장 스프링 클라우드 슬루스와 집킨을 이요한 분산추적

10장 마이크로 서비스의 배포


부록 A 데스크톱에서 클라우스 실행

부록 B OAuth2 그랜트 타입


내가 기존에 알고 있던 내용들은 주로 컨피그 서버나 유레카를 이용한 서비스 디스커버리, 그리고 Zuul 을 사용한 라우팅 정도만 약간 해본 정도였다. 그런데 목차에서 보면 알수 있듯이 그것 이외에 다양한 내용들이 있다. 실패 전략을 통한 복구 패턴(5장), 인증및보안(7장), 그리고 이벤트 처리(8장)가 수록되어있다. 그리고 마이크로서비스 하면 중요하게 생각해야할 모니터링에 대해서 9장에 잘 설명해 주고 있다. 


또 내가 OAuth 2 처음 공부할때에 grant type 이 잘 정의가 안되어서 이해하는데 어려움이 많았었는데 이 내용도 부록을 통해서 설명해주고 있어서 공부하고 있는 입장해서 정말 알찬 구성인것 같다. 



다음은 책 내용을 살펴보자.



코드에 대한 내용과 그 의미들이 코드와 함께 담겨져 있다. 개인적으로 이런 형태의 코드 설명을 좋아하는 편이다. 그냥 종이 위에 코드만 써있는 것보다는 주석 이외에 이렇게 설명을 추가해주면 이해하는데 도움이 많이 된다. 



그리고 내가 읽으면서 가장 맘에 드는 부분이다. 마이크로서비스에 대한 개념과 구성을 거의 빠짐없이 그림으로 설명을 다 해준다. 마이크로 서비스 자체가 작은 단위로 쪼개서 전체 시스템을 구성하기 때문에 머릿속에서 그 큰 그림을 떠올리기는 쉽지가 않다. 어디에서 부터 시작을 해야 할지 막막해질 때도 있다. 그런데 이 책에서 고맙게도 구성, 개념을 알기 쉽게 그림을 통해서 설명을 해준다. 이 부분이 이 책의 가장 큰 장점인것 같다. 


책의 전체적인 내용들을 봤을때에는 초보자들을 위한 책이기 보다는 어느정도 Spring Boot 에 대한 지식을 가지고 있는 개발자에게 도움이 되는 책인것 같다. Spring Boot 에 대한 책이 아니라서 Spring Boot를 모르는 사람이 보기에는 코드부터가 어려울 수 있다. 그래서 Spring Boot 로 개발을 해봐서 코드를 이해하는데에 문제가 없는 분들이 마이크로 서비스를 이해하는데 많은 도움을 줄수 있는 책이라고 생각된다. 



728x90
반응형
반응형


지난번 Google Summit 에 이어 이번에는 피보탈에서 주최하는 SpringOne Tour 세미나에 참석을 했다.


https://springonetour.io/2018/seoul


우연히 Facebook 타임라인에 뜬 세미나 일정과 Agenda 를 보고 신청을 했었다. Spring 관련 세미나라서 내용에 대한 기대가 컸다. 세미나의 전체적인 주제는 Reactive 와 Cloud 관련 내용들이 많이 있었다. 회사에서 많이 쓰지는 않는 내용들이었지만 그래도 공부하면서 봤었던 유투브에서 봤던 내용들이어서 어느정도 이해할 수 있었다. 그리고 대부분 라이브 코딩이 포함되어 있어서 오히려 더 도움이 됐다. 


세션 요약

1. Reactive Spring with Spring Boot 2.0 - Mark Heckler


화면에는 Reactive Java 라고 되어있지만 다음 페이지에 바로 Reactive Kotlin 으로 변경했다. 라이브 데모 소스도 Kotlin 으로 작성을 했지만 눈으로 따라가는데에는 어렵지 않았다. 내용은 reactive programing 에 대한 내용이었다. 기존에 application 을 유지하기 위해 많은 양의 Thread 가 필요 했다면 이제는 non-blocking 이다 event-driven 을 이용해서 그 Thread 를 좀더 줄일수 있다, 아니 일정 수준으로 계속 유지 할수 있다는 내용 이었다. 그리고 backpressure 라는 내용이 있었는데 그부분은 좀 생소했다. 처음 듣는 단어라서 좀더 찾아봐야 할것 같다. 


참고사이트

http://www.reactive-streams.org/

https://projectreactor.io/

https://github.com/mkheck/FSR


2. Cloud-Native Spring - Josh Long

두번째 세션에서는 Josh Long 의 발표가 있었다. spring 관련 내용을 찾다 보면 이분 내용의 글들이 많이 있었는데 실제로 보니 정말 유쾌한 분이었다. 유머 감각도 있고. 그리고 놀라운것은 코드 작성 속도가 정말 빠르다. 말도 빨리 하는데 코드 작성하는 속도는 말보다 빠르다. 짧은 시간내에 라이브 코딩으로 gateway도 구현하는 라이브 코딩을 보여주었다. 그리고 역시나 처음본 rsocket?? 을 이용해서 코드를 바꿔서 보여주기도 했다. 


3. Spring Cloud Gateway - Younjin Jeong


API Gateway 에 대한 내용이었다. 그중 Netflix 에서 Zuul 을 사용했는데 asynchronous  non-blocking을 지원하기 위해 Zuul 2 를 새로 만들었다고 한다. 그런데 이게 non-blocking 이다 보니 기존 버전과 하위 호환성은 없다고 한다. 완전 새로은 제품이라고 생각하면 된다. Netflix 에서 자기들이 마이크로서비스를 위해서 사용했던 기술들을 라이브러리로 해서 많이 나왔지만 이게 내부에서 사용했던 것들이라서 소스코드가 깔끔하지 않다는 의견이 있었다. 약간 기억이 정확하지는 않지만 Spring 에서는 Zuul 2 는 아직 지원을 않하고 Zuul 1 을 지원한다고 했던것 같다. (정확하지 않음)


그리고 Zuul 을 설명해주면서 Ribbon 하고 비교설명해준게 내게 도움이 많이 됐다. 전에도 이 2개를 헷갈리고 뭔차이지 라는 생각은 하고 있었는데 오늘 설명을 듣고 좀 명확해 졌다.


Zuul 은 외부 트래픽에 대해서 이 트래픽을 어떤 서비스로 보낼지를 결졍해준다. 

Ribbon 은 Zuul 에서 결정된 서비스중 어느곳으로 보낼지를 결정해준다. 


또 Netfilx 에서 자기들이 직접 개발 운영하면서 Gateway 를 설계할때 Concurrent Connection, Thread Count, Latency 를 잘 판단해서 설계를 해야 한다고 했다. 저건 Youtube 동영상을 캡쳐한 화면인데 시간이 될때 한번 봐야겠다. 




참고사이트

https://github.com/spring-cloud/spring-cloud-gateway

https://github.com/spring-cloud-samples/spring-cloud-gateway-sample

http://slides.com/spencer/spring-cloud-gateway

https://github.com/ryanjbaxter/gateway-s1p-2018



4. Cloud Event Drive Architectures with Spring Cloud Stream 2.0 - Jakub Pilimon


세션 중반까지 잘 듣다가 잠깐 졸았던게 후회되는 세션이었다. 대체 왜 졸았을까.......



먼저 개발을 하기 전에 Event Storming 에 대한 이야기 이다. Event Storming 은 실제 현업과 이야기를 하면서 그들이 사용하고 있는 시스템에 대해서 이야기를 하는것이다. 기술적인 내용 없이 어떤 기능들이 있는지 이야기를 하는 부분이다. Event Storming 을 통해서 우리는 그 대화에서 Event 들을 도출해낸다. 


또 Event Storming 을 통해서 도출된 Event 에 대해서 우리가 해야 할 부분은 이 event 가 동작해야 하는 조건들을 추가하는 것이다. 바로 Event 에 대한 트리거를 확인 하는 작업이다. 


하아.. 이 다음이 문제다. 잠깐 졸고 일어났더니 라이브 코딩이 한창이었다. 그런데 내용을 보니 event 를 저장해서 뭔가를 하는 부분이었는데 그게 바로 Event Sourcing 부분이었던것 같다. 정신을 차리고 코드를 따라가보긴 했는데 결과적으로 주된 내용은 어플리케이션에서 트랜잭션이 일어날 경우 바로 DB 에서 처리하는게 아니라 그걸 발생시킨 Event를 하나씩 저장을 해서 처리를 한다는 것이었다.


그럼 왜 이렇게 하느냐에 대한 설명이 나왔다. 이해가 가는 부분도 있고 안되는 부분도 있어서 좀더 공부를 해봐야 할것 같다. 


- 장점

  이벤트를 통해서 모델에 대한 오딧이 가능하다. (이건 좀 이해가 안갔다... )

  이벤트 기반으로 히스토리 확인이 가능하다.

  특정 이벤트 별로 확인 및 분석이 가능하다.

- 단점

  코드가 많고 복잡하다.

  기존에 만들었던 방식과 다르기 때문에 사고의 전환이 필요하다.


참고사이트

https://github.com/ddd-by-examples

https://github.com/pilloPl/credit-cards-producer

https://github.com/pilloPl/credit-cards-consumer

http://pillopl.github.io/


5. Spring, Functions, Serverless and You - Nate Schutta

이번 세션에서는 아키텍처에 대한 내용들이 주제 였다. 세미나 가면 자주 듣던 예인데 전에는 Server를 애완동물처럼 애지중지 하게 다뤘지만 이제는 Server 가 애완동물이 아닌 가축으로 생각되고 있다는 이야기 이다. 다시 말해 Server가 죽으면 교체한다는 의미이다. 

위 사진에서 보여 주듯이 위로 올라갈 수록 Complexity 가 줄어들고 운영하기 좋아지기 때문에 최대한 Serverless 로 올려야 한다는 내용이었다. (4번 세션이후로 점점 집중력이 떨어져서 잘 듣지 못했다..)


6. Spring Boot & Cloud on Pivotal application Service - Younjin Jeong

이번 세션에서는 Pivotal 에서 어떤 서비스들을 제공하고 있고 어떤 플랫폼들이 있는지에 대한 내용이 대부분을 차지 했다. 

내용중에 이부분이 좀 와닿았다. 개발자들이 운영을 하는데 얼마나 시간을 소비하고 있는가. 새로운 기능을 만드는 것보다 대부분의 시간이 기존에 만들었던 거를 수정하고 디버깅하는데에 시간이 사용된다. 이걸 무슨 단어가 있었는데 생각이 안난다. 결과적으로 저렇게 되면 개인에게도 손해고 회사에도 손해이다. 

그래서 필요한게 Full Cycle Developers 다. Netflix 에서 한 말이고 어느정도 와닿는다. 하지만 저렇게 되려면 개인만 해서는 안되고 조직 자체가 그렇게 변해야 하기 때문에 쉬운 일은 아니다. 


Full Cycle Developers at Netflix — Operate What You Build


7. Using Spinnaker to Create a Development Workflow on Kubernetes - Paul czarkowski

마지막 세션에서는 Kubernetes 에 대한 내용이 많이 나왔다. 최근에 자주 보던 내용이어서 많이 집중해서 보지는 않았는데 마지막에 나온 Spinnaker 에 대해서는 좀 찾아 봐야겠다. 


마무리


마지막에 운좋게 당첨되서 "클라우드 네이티브 자바" 책을 받아왔다. 세션 중간에 책 사서 Josh Long 한테 사인 받을까 했었는데 참길 잘했다. ^^ 

앞에서도 말했지만 세션 전체적으로 모르는 내용이 많이 있긴 했지만 중간중간 중복해서 설명되는 내용도 있었고 코드를 따라가다 보면 이해가 되는 내용도 많았다. 역시 개발자는 코드로 대화를 할수 있어야 한다는게 괜한 말이 아니었다. ^^;; 최근 GCP 공부하다 보니 Spring 쪽은 약간 소홀한 면이 있었는데 오늘 세미나를 듣고 보니 잠깐 쉬는동한 공부해야 할게 참 많아졌구나라고 느꼈다. 좀더 분발해야 할것 같고 궁금했던 부분들에 대해서는 빨리 찾아봐야겠다. 


Action Item

Backpressure 란 무엇인지 찾아보자.

rsocket 에 대해서 찾아보자. Facebook 에서 사용한다고 하는데??

Zipkin 사용해보면 좋을것 같다.

Event Sourcing 에 대해서 개념 파악해보고 소스한번 다시 보자.

Spinnaker 에 대해서 알아보자. 



728x90
반응형
반응형

Spring Security 를 적용하는 내용을 처음부터 차근차근 정리를 해보려고 한다. 

목표는 Spring Security 를 공부하면서 각각의 기능들을 적용해보는것이다. 진행하다보면 Spring Security 뿐만 아니라 다른 내용들도 점점 추가될것 같다. 다 만들고 나서는 git에 소스를 공유할 생각이다. ^^;; 언제가 될지는 잘 모르겠다.


환경 : java 1.8, Spring Boot 1.5.3 Release, Maria DB, JPA, gradle


build.gradle

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
buildscript {
    ext {
        springBootVersion = '1.5.3.RELEASE'
    }
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}
 
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
 
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
 
repositories {
    jcenter()
    mavenCentral()
}
 
 
dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-security')
 
    testCompile('org.springframework.boot:spring-boot-starter-test')
 
    runtime ('org.mariadb.jdbc:mariadb-java-client')
}
cs



아직 초반이어서 라이브러리가 몇개 없다. spring-boot 에서 사용하는 jpa, security, test, web 라이브러리가 끝이다. 그리고 DB를 사용하기 위한 mariadb client까지만 추가되어있다.


도메인.

Account.java

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class Account {
    @Id
    private String loingId;
 
    private String username;
 
    private String password;
 
    private String email;
 
    private boolean enabled;
}
cs


Account 도메인이 있다. 만들기는 더 여러개 만들어놓았는데 우선은 이것만 필요해서 적었다. 위 Account.java 소스에는 getter/setter 메소드는 삭제하고 올렸다. (너무 길어서)


다음은 Account 관련 Service와 Repository 이다. 


AccountRepository.java

1
2
public interface AccountRepository extends JpaRepository<Account, String> {
}
cs


AccountService.java

1
2
3
4
public interface AccountService {
    Account get(String loginId);
}
 
cs


AccountServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
@Service
public class AccountServiceImpl implements AccountService {
 
    @Autowired
    private AccountRepository accountRepository;
 
    @Override
    public Account get(String loginId) {
        return accountRepository.findOne(loginId);
    }
}
cs


Repository를 다이렉트로 호출해도 되긴 하지만 아무래도 구조상 service 레이어가 있는게 맞다고 판단해서 repository는 Service 에서 호출하도록 한번 감쌌다. 지금은 간단히 호출만 하지만 나중에는 로직도 들어갈것이 예상된다.


CustomUserDetailService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class CustomUserDetailService implements UserDetailsService{
 
    @Autowired
    private AccountService accountService;
 
    @Override
    public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException {
 
        Account account = accountService.get(loginId);
 
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
 
        User user = new User(account.getLoingId(), account.getPassword(), grantedAuthorities);
 
        return user;
    }
}
cs


UserDetailsService에 있는 loadUserByUsername 메소드를 제정의 해서 UserDetails 객체를 정의해준다. UserDetails는 사용자의 인증정보를 담고있다. 위에서 Account Service에서 loginId로 정보를 조회해서 가져온 id, password, 권한(아직 미구현으로 객체만 생성했다) 정보를 user로 생성해주고 있다.




ResourceSecurityConfiguration.java

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@EnableGlobalAuthentication
public class ResourceSecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private CustomUserDetailService customUserDetailService;
 
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.customUserDetailService);
    }
}
 
cs


WebSecurityConfigurerAdapter에 있는 init 메소드를 사용해서 AuthenticationManangerBuilder에 userDetailService를 내가 새로 만든 CustomUserDetailService를 사용하겠다고 설정해준다.


StudySpringApplication.java

1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class StudySpringApplication {
 
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(StudySpringApplication.class);
 
        app.run(args);
    }
}
 
cs


application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server:
  port: 9000
 
spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/holmes
    username: root
    validation-query: select 1
    test-while-idle: true
    time-between-eviction-runs-millis: 300000
    test-on-borrow: false
 
  jpa:
    database: mysql
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.MySQLDialect
        default_schema: holmes
cs


이제 어플리케이션을 실행해보면 로그인 페이지가 나온다. 





위에 소스와 약간 차이가 있을수 있지만 아래 Git repository 에 가면 소스를 확인할 수 있다. 


https://github.com/blusky10/study_spring


728x90
반응형
반응형

테스트케이스를 만들어서 작업을 하면 소스코드가 수정될 경우 코드를 테스트 해보기가 참 수월하다. 그런데 이 테스트 케이스 작성하는게 생각보다 만만치는 않다. 

실제 DB 를 읽어서 테스트를 해야 하는지. 아니면 Mock 객체를 정의를 해서 사용을 해야 하는지. 실제 DB 를 사용할 경우 저장된 data 가 변경이 되어서 구현했을 당시 테스트 케이스는 Pass였지만 나중에 빌드 시점에 테스트 케이스가 실행될 경우에 Fail 이 나면 어떻게 할것인지. 

생각해보면 그냥 서비스 구현해서 화면 띄우고 버튼 눌러서 테스트 하는것이 더 편할지도 모른다는 생각이 들기도 한다. 

작성할 때마나 서비스 테스트,  repository테스트, 컨트롤러 테스트에 대해서 구글링 하면서 작성을 하다보니 뭔가 남는게 없는것 같아서 샘플을 한번 만들어보기로 했다. 

 

최근에 필요하기도 했고 나중에 또 써먹을 일도 있을것 같아서 Controller 테스트 케이스를 작성한 것을 공유해 본다.

 

각각의 구성은 아래와 같이 되어있다. 

(java : 1.8, SpringBoot : 1.5.3)

 

Book.java

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long bookId;

    private String title;

    // Getter & Setter 생략
}

 

BookRepository.java

public interface BookRepository extends JpaRepository<Book, Long>{}

BookService.java

public interface BookService {
    Book getBook(Long id);
}
 

BookServiceImpl.java

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookRepository bookRepository;

    @Override
    public Book getBook(Long id) {
        return bookRepository.findOne(id);
    }
}
 

BookController.java

@RestController
public class BookController {

    @Autowired
    private BookService bookService;

    @RequestMapping(value = "/book/{bookId}", method = RequestMethod.GET, produces = "application/json")
    public Book getBook(@PathVariable Long bookId){
        return bookService.getBook(bookId);
    }
}

/book/{bookId} 라는 url 로 request 를 보내면 bookId 에 맞는 Book 객체를 리턴해주면 되는 형태이다. 테스트 케이스 없이 테스트 하려면 톰캣으로 띄워놓고 실제로 화면에서 위에 정의한 서비스를 호출하는 컴포넌트를 클릭해서 정상 동작을 하는지 확인해봐야한다. 그러다가 소스에 글자라도 하나 틀리면 수정한다음에 다시 톰캣 재기동을 하는 번거로운 작업을 진행해야 한다. 

 

 

 

 

 

 

 

 

 

 

이런 번거로움을 피하기 위해 테스트 케이스를 작성해 보았다.

@RunWith(SpringRunner.class)
@SpringBootTest
public class BookControllerTest {

    private MockMvc mockMvc;

    @MockBean
    BookController bookController;

    @Before
    public void setup(){
        mockMvc = MockMvcBuilders.standaloneSetup(bookController).build();
    }


    @Test
    public void getBookTest() throws Exception {
        given(this.bookController.getBook(new Long(1)))
                .willReturn(new Book("Homes"));

        mockMvc.perform(get("/book/{bookId}", 1))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$['title']", containsString("Homes")))
                .andDo(print());
    }
}

BookController를  MockBean으로 정의를 해주었다. 그리고 BookController 의 getBook메소드에 파라메터가 1이 들어왔을 때 리턴 받는 결과를 미리 정의한다. (18~19 라인) 그리고 화면에서 요청하는 것처럼 Request를 수행해준다.  perform에 있는 파라메터를 보면 get 메소드를 호출하게 되며 파라메터로 1값을 넣어서 실행을 한다. OK 응답을 받게 되고 리턴 받는객체의 title이 "Homes"  인지 비교를 한다. 19라인에서 책 이름을 미리 Homes  로 정의 했기때문에 테스트는  Pass가 된다. 마지막에 andDo(print()) 는 실제 수행된 로그가 콘솔창을 통해 볼수 있도록 처리해 준것이다.

 

처음에 만들때는 좀 삽질을 하긴 했지만 만들고 보니 앞으로 자주 써먹을것 같다. 앞으로도 바쁘지만 테스트케이스를 만들면서 코드 작성을 하도록 해야겠다.

 

참고로 위 소스를 작성한 gradle.build 파일은 아래와 같다.

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')

    runtime('group:com.h2database:h2');

    testCompile('group:com.jayway.jsonpath:json-path')

    testCompile('org.springframework.boot:spring-boot-starter-test')
}
 

 

728x90
반응형

'Development > Java' 카테고리의 다른 글

[OAuth] Oauth의 간략한 흐름.  (0) 2017.07.04
[Spring Security]간단 Spring Security  (0) 2017.06.27
[Spring]Jasypt 를 이용한 properties 암호화  (6) 2017.04.25
[SpringCloud]Spring Config..  (0) 2016.01.26
spring Cache  (0) 2015.12.05
반응형


프로젝트 내부에는 설정파일들이 많이 있다. 대표적인 항목이 DB 접속 정보가 있다. 

그런데 이 접속정보에는 ID, PASSWORD 가 항상 존재 한다. ID는 상관이 없지만 PASSWORD 정보가 파일 내부에 평문으로 적혀있으면 외부에 노출될 위험이 있다. 그래서 암호화를 해야 한다. 


Jasypt를 이용하면 이런 항목들을 쉽게 암호화 할 수 있다. 



먼저 라이브러리를 다운로드 받는다.


http://www.jasypt.org/download.html


사이트에 들어가보면 상단에 DOWNLOAD JASYPT 라는 링크가 있다. 그 걸 누르면 라이브러리를 다운로드 받을 수 있다. 

이 글을 쓰는 시점의 버전은 1.9.2 이다. 


다운로드 한다음 사용 방법은 간단하다. 압축을 푼후에 bin 폴더로 이동한다. 


그리고 콘솔창(윈도우cmd 창)에서 아래와 같이 입력한다. 




encrypt input="password" password="pwkey" algorithm="PBEWITHMD5ANDDES" 



input 항목에는 실제 사용하고 있는 패스워드를 입력하면 되고 password 항목에는 암호화된 값을 복호화 할때 사용되는 key 값을 넣으면 된다. 임의로 정해서 넣으면 된다.


명령어 실행 결과.



----ARGUMENTS-------------------

algorithm: PBEWITHMD5ANDDES

input: password

password: pwkey

----OUTPUT----------------------

oQV892dssDi5Xzs9tQoVuaqyRaFa7Za5 



여기에서 보이는 OUTPUT 항목이 실제 암호화 된 값이 된다.


이제 암호화 된 값 생성까지는 완료가 됐고 실제 spring 프로젝트에 적용을 하면 된다.


먼저 Jasypt 라이브러리르 추가한다. 


Mvn repository 에 가서 jasypt 검색을 하면 정말 많이 나온다.  최신버전으로 찾아서 넣으면 되긴 하는데 여기에서 주의할 점이 있다. 


최신버전의 라이브러를 추가하고 어플리케이션을 run 했을때 version  관련 오류가 날수가 있다. 이경우에는 현재 Spring 버전이 jasypt 최신버전과 호환이 안되던지 아니면 jdk 버전이 호환이 안되던지 둘중 하나이다. 실제로 jasypt 라이브러리 depency를 보면 spring 4.3.8 Release 와 dependency 가 되어있다. 그래서 주의를 해야 한다.


나 같은 경우는 실제로 버전 충돌때문에 build.gradle 에 아래와 같이 추가를 했다. (spring boot 버전도 1.3.8 아래였고 jdk 버전도 7이었다.)


compile('com.github.ulisesbocchio:jasypt-spring-boot-starter:1.4-java7')




spring 설정 파일에 아래와 같이 정의를 한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    <bean id="encryptorConfig" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
        <property name="algorithm" value="PBEWithMD5AndDES" />
        <property name="password" value="pwkey" />
    </bean>
     
    <bean id="encryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
        <property name="config" ref="encryptorConfig" />
    </bean>
     
    <bean class="org.jasypt.spring3.properties.EncryptablePropertyPlaceholderConfigurer">
        <constructor-arg ref="encryptor" />
        <property name="locations">
            <list>
                <value>classpath:/properties/db.properties</value>
            </list>
        </property>
    </bean>
cs


그리고 마지막으로 설정 파일의 password 값을 암호화 한 값으로 넣어준다. 반드시 ENC라고 쓰고 괄호안에 값을 넣어야 한다.


1
datasource.password=ENC(EywTY3v00EbqKyxlLzkjag==)
cs


이렇게 하면 password 값을 읽어들일때 암호화 된 값을 읽어서 자동으로 복호화 한다.


Spring boot 일 경우에는 아래와 같이 설정해주면 된다.


먼저 Encryptor 를 정의한 class를 만들어준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class PropertyEncryptConfiguration {
 
   @Bean
   static public StandardPBEStringEncryptor stringEncryptor() {
      StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
      EnvironmentPBEConfig config = new EnvironmentPBEConfig();
      config.setPassword("pwkey");
      config.setAlgorithm("PBEWITHMD5ANDDES");
      encryptor.setConfig(config);
      return encryptor;
   }
}
cs



그리고 main class 에 @EnableEncryptableProperties 를 추가해준다. 그럼 설정이 마무리 된다. 


암호화 하는 과정이 번거롭다면 그 부분만 따로 테스트 케이스를 만들어 놓는것도 좋은 방법이다.


728x90
반응형

'Development > Java' 카테고리의 다른 글

[Spring Security]간단 Spring Security  (0) 2017.06.27
[Spring]Controller Test 하기  (0) 2017.06.12
[SpringCloud]Spring Config..  (0) 2016.01.26
spring Cache  (0) 2015.12.05
Spring propagation  (0) 2015.12.01
반응형

myapplication 이라는 이름을 가지고 있고 sample 이라는 profile을 설정했을경우 우선순위는 다음과 같다.


1. myapplication-sample.yml

2. myapplication.yml

3. myapplication.properties



728x90
반응형

'Development > Java' 카테고리의 다른 글

[Spring]Controller Test 하기  (0) 2017.06.12
[Spring]Jasypt 를 이용한 properties 암호화  (6) 2017.04.25
spring Cache  (0) 2015.12.05
Spring propagation  (0) 2015.12.01
[JPA]Persistence Context  (0) 2015.08.25
반응형

@Cacheable

캐시할 메서드를 지정한다. 

위 어노테이션을 사용한 메서드는 결과를 캐시에 저장하기 때문에 뒤이은 호출에서는 실제로 메서드를 실행하지 않고 캐시에 저장된 값을 반환한다.


@CachePut

메서드 실행에 영향을 주지 않고 캐시를 갱신해야 하는 경우.

메서드를 항상 실행하고 그 결과를 캐시에 보관 한다.


@CacheEvict

캐시에 데이터를 제거하는 트리거로 동작하는 메서드 이다.


728x90
반응형

'Development > Java' 카테고리의 다른 글

[Spring]Jasypt 를 이용한 properties 암호화  (6) 2017.04.25
[SpringCloud]Spring Config..  (0) 2016.01.26
Spring propagation  (0) 2015.12.01
[JPA]Persistence Context  (0) 2015.08.25
[JPA]Entity 생명주기  (0) 2015.08.12

+ Recent posts