Developing CNA - HiroSung/Study GitHub Wiki

Intro

Day1

EventStorming

  • MSA School - 일반적인 CNA 구현
  • bounded context 단위로 서비스의 단위를 구성함.
  • EventStorming의 마지막은
    • Policy는 누가 할 것인지 작업이 필요함. ==> Context Mapping
    • Event와 Policy간에 연결을 하면 Pub/Sub 이 생성됨. ==> 비동기. Wating 없음. 호출하고 끝남. Queue모듈이 필요함.
    • Event와 Command간에 연결하면 Req/Res ==> 동기. Wating.
    • 조회는 Event가 아님.
    • 시나리오가 설명되어야 함.
      • 고객이 주문을 하게 되면 "주문됨"이라는 이벤트를 발생하고, Ship를 호출하여 배송에서느 Shipped 라는 이벤트를 발생함.
      • Event는 Aggregate에서 발생됨.
  • CNA가 지향하는 EventStorming이 Arch는 Pub/Sub 이다.
  • RESTAPI
    • "http REST_METHOD, url"
    • Method : POST(생성), GET(조회), PUT/PATCH(수정), DELTE(삭제)
  • HTTPie (https://httpie.org/)

일반적인 CNA 구현

  • HTTPie 설치
  • Spring Initializer 에서 POM 생성 - H2, JPA, Rest Repository 추가
  • 코딩
    • Aggregate 생성
    • Command 생성
      • CF : netstat -ano | findstr "PID :808"
    • MVN > demo > Plugins > spring-boot > spring-boot:run 실행하여 tomcat 수행함.
    • console에 "started" 메시지 확인
C:\CNA\demo>http http://localhost:8080
HTTP/1.1 200
Connection: keep-alive
Content-Type: application/hal+json
Date: Mon, 10 Aug 2020 05:46:54 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

{
    "_links": {
        "products": {
            "href": "http://localhost:8080/products"
        },
        "profile": {
            "href": "http://localhost:8080/profile"
        }
    }
}
C:\CNA\demo>
  • Event 생성
    • 이벤트의 출처는 Aggregate이며, Aggregate 가지는 속성으로 데이터를 처리할 수 있음.
    • ProductChanged
    • 우리팀의 이벤트는 타팀의 요구에 의해서 오픈(생성)하게 됨.
  • Event 발행 (Event Raise)
    • 나 다음에 수행할 것을 지정하는것 Trigger 하게됨.
    • POST / PATCH / DELETE
  • 카프카 설치 / 주키퍼 설치 . 실행
    • Middleware - Kafka
    • 카프카는 분산 환경 코디네이터(Coordinator)인 주키퍼 위에서 작동을 합니다. 주키퍼를 먼저 실행하고, 카프카를 이어서 실행합니다.
    • POM.xml 수정 후, Reimport 해야함.
    • 카프카 설치시 기본 포트가 9092

    #kafka-console-consumer.bat --bootstrap-server http://localhost:9092 --topic shop --from-beginning

    • http POST localhost:8080/products name=“TV” stock=10 수행하여 콘솔에 찍히는 내용 확인.
  • 이벤트를 수신하는 Policy 를 생성
    • Event에 대응되는 Policy(폴리시)는 다른 마이크로서비스(팀)에서 수신 합니다. 즉, 상품 서비스에서 ProductChanged 이벤트가 발생하면 주문이나 배송 서비스에서 이를 수신 후 각 서비스에 맞는 Biz-Logic을 처리하지만, 편의상 Kafka로부터 메세지 수신만 확인합니다.

Day2 - 도구기반(MSAEz) CNA구현

  • User Stories
  > 고객이 주문을 하면, 주문정보를 바탕으로 배송이 시작된다.
  > 고객이 주문을 취소하게되면, 주문정보는 삭제되나, 배송에서는 (사후, 활용 위해) 취소장부를 별도 저장한다.
  > 주문취소는 반드시 배송취소가 전제되어야 한다. ==> feignclient 사용
  > 주문과 배송 MSA는 게이트웨이를 통해 고객과 통신한다.

주문/배송을 위한 EventStorming 모델링

  • MSAEZ 툴을 활용 (http://msaez.io/)
  • 이벤트 Trigger 생성시
    • Post Persist로 해야 생성 후, Key값에 해당하는 주문번호를 Kafka로 전달함.
    • OrderCenceled의 Cancel command 는 POST 로 설정
  • PolicyHandler.java
    • policy는 이벤트에 귀를 기울이는 역할.
    • 주문의 기능을 가져와서 Delivery 처리하도록 하는것
    • 주문의 정보를 가져와서 내부적으로 처리할 로직을 구현 하는 것.
    @StreamListener(KafkaProcessor.INPUT)   // kafka를 해바라기 하고 있는 코드
    public void wheneverOrdered_Ship(@Payload Ordered ordered){

        if(ordered.isMe()){
            System.out.println("##### listener Ship : " + ordered.toJson());
            // TODO 
        }
    }
  • context mapping 종류
    1. ordered 같은 것은 코레오그래피, choreography, : 중간에 연결하고 알아서 처리
    2. ordercanceled 같은것은 orchestration type : 모든것을 중간 관리
  • 툴 : 피보탈의 보리스
  • 비기능 - 게이트웨이
    • DMZ 밖에 노출되는 IP에서 서비스로 라우팅하는 역할
    • 콩, IBM, Istio ingress , Nginx ...
  • Project > 코드 를 선택하면 , order, delivery 를 코드로 자동 생성해줌.
    • order
    • delivery
    • gateway
    • application.yml 내용 확인
    • docker 파일 내용 확인

Intelij 코딩

  • 소스 다운로딩
  • InteliJ 폴더 선택
  • 스타트
    • 주키퍼 스타트 : zookeeper-server-start.bat ../../config/zookeeper.properties
    • 카프카 스타트 : kafka-server-start.bat ../../config/server.properties
    • 이벤트수신 모니터 : kafka-console-consumer.bat --bootstrap-server http://localhost:9092 --topic local --from-beginning
    • pom.xml > plugin - spring-boot:run 실행 (order, delivery, gateway)
      • Kafka ; 토픽 : 특정 데이터 스트림. 메시지를 구분하는 통로
# netstat -ano | findstr PID "808"
# http GET http://localhost:8081
# http POST http://localhost:8081/orders productId=1001 qty=10
  • order에 있는 Ordered가 delivery에 Ordered로 똑같이 존재함. why?
    • Contract test
    • Event & Policy 규약임
  • 동기호출
    • spring 에서 RestTemplate
    • cloud는 FeignClient 사용함.
    • 서버 to 서버
    • interface, FeignClient 설정하면 됨.
@FeignClient(name="delivery", url="http://localhost:8082")  // cloud 안에서 호출하는 주소.  delivery
public interface CancellationService {

    @RequestMapping(method= RequestMethod.POST, path="/cancellations")
    public void cancel(@RequestBody Cancellation cancellation);

}
  • Order 하는 부분
    @PreRemove
    public void onPreRemove(){
        OrderCanceled orderCanceled = new OrderCanceled();
        BeanUtils.copyProperties(this, orderCanceled);
        orderCanceled.publishAfterCommit();

        //Following code causes dependency to external APIs
        // it is NOT A GOOD PRACTICE. instead, Event-Policy mapping is recommended.

        local.external.Cancellation cancellation = new local.external.Cancellation();
        // mappings goes here. 아래내용 추가
        cancellation.setOrderId(this.getId());
        cancellation.setStatus("DELIVERY CANCELLED");

        OrderApplication.applicationContext.getBean(local.external.CancellationService.class)
            .cancel(cancellation);


    }

  • order 재시작
# http POST http://localhost:8081/orders productId=1 qty=10
# http POST http://localhost:8081/orders productId=2 qty=10
# http DELETE http://localhost:8082/cancellations/1
  • CancelationService url을 yml 에 참조하여 사용하도록 설정

Day3

  • CQRS, MView

  • User Stories

  > 고객이 주문을 하면, 주문정보를 바탕으로 배송이 시작된다.
  > 고객이 주문을 취소하게되면, 주문정보는 삭제되나, 배송에서는 (사후, 활용 위해) 취소장부를 별도 저장한다.
  > 주문취소는 반드시 배송취소가 전제되어야 한다. ==> feignclient 사용
  > 주문과 배송 MSA는 게이트웨이를 통해 고객과 통신한다.

  추가요청사항
  > 

이벤트 드리븐 구현 샘플

View - Mypage

  • MSAEZ에서
    • View 추가하여
    • CQRS 선택
    • 속성 orderId, qty, deliveryId, status, productId
    • create when
      • 주문이 발생했을때 View Field에서 EvnetField에 매핑
      • Ordered - orderId = id, qty = qty
    • update when
      • Shipped - status = Sipped.status
      • DeliveryCanceled - orderId = orderId
    • boundedcontext 추가
      • customercenter
  • 코드 preview
    • customercenter가 추가됨
    • ViewHandler 추가됨

코딩

  • mypage를 InteliJ에 추가하고 gateway application.yml 에 라이팅정보 추가
---

spring:
  profiles: default
  cloud:
    gateway:
      routes:
        - id: order
          uri: http://localhost:8081
          predicates:
            - Path=/orders/** 
        - id: delivery
          uri: http://localhost:8082
          predicates:
            - Path=/deliveries/**,/cancellations/**
        - id: customercenter
          uri: http://localhost:8083
          predicates:
            - Path=/mypage/**
---

spring:
  profiles: docker
  cloud:
    gateway:
      routes:
        - id: order
          uri: http://order:8080
          predicates:
            - Path=/orders/** 
        - id: delivery
          uri: http://delivery:8080
          predicates:
            - Path=/deliveries/**,/cancellations/**
        - id: customercenter
          uri: http://customercenter:8080
          predicates:
            - Path=/mypage/**

git에 올리기

  • ubuntu에 mvn 설치
    • 없다면 설치 : sudo apt-get install maven
  • github에 repository 하나 생성
    • local\order 폴더로 이동
# git init
# git status
# git add .
# git commit -m "message"
# git remote add origin https://github.com/Hirosung/cna-customercenter.git
# git push -u origin master

ubuntu에서 dockerizing

  • git에 올린 소스 다운 받기

    git clone https://github.com/Hirosung/cna-order.git

  • cna-order 폴더로 이동
  • mvn으로 컴파일 아카이빙

    mvn package

  • 도커라이징 하기
  • admin26.azurerc.io/cna-order:v1

docker build -t admin26.azurerc.io/cna-order:v1 .

  • 확인

docker images

  • push

docker push admin26.azurecr.io/cna-order:v1

  • 기존 이미지 삭제

    docker images

Azure 로그인

  • 로그인
# az login -u [email protected] -p skccadmin1234!
# az aks get-credentials --resource-group admin26-rg --name admin26-aks
# kubectl config current-context
	> admin26-aks 
# kubectl get all
# kubectl get node
# kubectl create deploy my-nginx --image=nginx
# kubectl expose deploy my-nginx --port=8080
# kubectl create deploy my-nginx2 --image=nginx
# kubectl exec -it ... my-nginx2 -- /bin/bash
root@my-nginx2.. # curl http://my-nginx
root@my-nginx2.. # curl http://my-nginx.default.svc.cluster.local
                         서비스명.네임스페이스명
# az acr login --name admin26

ubuntu에서 kafka

  • 헬름 설정
    • 쿠버네티스에 카프카 설치 및 실행
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
kubectl --namespace kube-system create sa tiller      # helm 의 설치관리자를 위한 시스템 사용자 생성
kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller
helm init --service-account tiller

kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
helm repo update
helm install --name my-kafka --namespace kafka incubator/kafka
  • 수행된 kafka 확인

watch kubectl get all -n kafka

여기서 부터는 모르겠다...

Circuit Breaker

kiali

siege