Developing CNA - HiroSung/Study GitHub Wiki
Intro
-
final Assessment : 9/7~
- CQRS View๋ฅผ ๋ง๋ค์ด์ผ ํจ.
- ์๋๋ฆฌ์ค > BackLog > ์ด๋ฒคํธ์คํ ๋ฐ ํ๊ฒ ๊ฐ๋ฐ
-
CNA ์จ๋ผ์ธ Lab ๊ต์ฌ : http://msaschool.io
- ์ค๊ณ/๊ตฌํ/์ด์๋จ๊ณ์ ๊ตฌํ ๋ถํฐ ์งํ ์์
-
์ด๋ฒคํธ ์คํ ๋ฐ ์จ๋ผ์ธ : http://msaez.io/
-
๋ก์ปฌ ๊ฐ๋ฐ์ ํ์ํ ์ค์นSW . windows : JDK, IntelliJ . CNA ํด๋ผ์ฐ๋ ์คํํ๊ฒฝ : Local Ubuntu 18.04
-
์ฌ์ ํ์ต
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/)
- ์จ๋ผ์ธ ์ฝ์ ํด์.
- ์ค์น : https://github.com/TheOpenCloudEngine/uEngine-cloud/wiki/Httpie-%EC%84%A4%EC%B9%98
- Hands-On Target Server : http://jsonplaceholder.typicode.com/todos
์ผ๋ฐ์ ์ธ 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 ์ข
๋ฅ
- ordered ๊ฐ์ ๊ฒ์ ์ฝ๋ ์ค๊ทธ๋ํผ, choreography, : ์ค๊ฐ์ ์ฐ๊ฒฐํ๊ณ ์์์ ์ฒ๋ฆฌ
- 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/**
- customercenter ์ํ
- ์กฐํ๋๋ ๋ด์ฉ ํ์ธ
http://localhost:8083/mypages/1
http GET
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์ ์ฌ๋ฆฐ ์์ค ๋ค์ด ๋ฐ๊ธฐ
- 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
์ฌ๊ธฐ์ ๋ถํฐ๋ ๋ชจ๋ฅด๊ฒ ๋ค...
- MSA๊ต์ก workflowy - https://workflowy.com/s/msa/27a0ioMCzlpV04Ib#/69f581576ade
Circuit Breaker
- ๋ฐฐ์ก(delivery) ์๋น์ค์ Circuit Breaker ์ค์น
kiali
siege
- Auto Scale-Out