직접 구축하기 vs 돈내고 쓰기

이성적으로는 돈 내고 쓰면서 빠르게 개발하는게 낫다는걸 알지만
하나하나 구축하려는 욕심이 든다
적정기준을 정해놓고 따르는게 좋을 것 같은데

서비스 구축을 하면서 사용해야 하는 서비스가 몇가지 있는데

  • 인프라
    • 그냥 서버.. linux, unix, windwos ..
    • k8s cluster
    • object storage
    • cdn
  • DevOps
    • 빌드
    • 배포
  • Logging & 모니터링
    • 로그수집
    • 모니터링
    • 알림

구축하는데 들어가는 비용이 이익을 상회하지 않는 경우
비용: 시간, 돈, 인력
이익: 만족감, 기술발전, 속도, 돈

비교

인프라

IDC에 서버 올려서 직접 구축하면 제일 싸긴하다… 효율적으로 사용할 수 없다.
초기비용이 크고 서버 관리하는 기술도 생각보다 어렵고
경험이 없으면 삽질을 엄청 많이 하게 된다
코드만 만지던 사람들이 생각도 못한 변수가…

그리고 서버를 코드화 할 수 없으면 곤란한 상황이 많이 발생한다.
메이저 클라우드 업체를 쓰면 서버를 완전 코드화할 수 있다.

  • AWS
  • GCP
  • Azure
  • Heroku

서버만 쓸 수도 있지만 클러스터까지 쓸 수도 있고

  • k8s
  • ecs

네이버 클라우드 등 국내 서비스는 안됨. XXX

CDN, ObjectStorage는 클라우드플레어 등 다른 회사를 써도 되고 메이저 클라우드를 써도 되는데 다 코드화가 가능하다.
코드화가 가능하면 인프라 구축이 매우 쉬워진다.
SI도 아닌데 한번 구축하면 끝이지 왜 환경을 재현해야 하냐고???? 하는 경우가 있는데

  • CloudFlare

인프라 코드화의 장점

  • 테스트 환경 구축: production 환경에
  • 서비스 확장이 간편: 인프라 규모를 확장할 때 오류 가능성이 낮다.
  • 테스트 자동화가

DevOps

위에 있는거에서 DevOps는 코드화 해서 쉽게 할 수 있고
githubaction같은 무료서비스도 많으니 그냥 써도 된다. 서버를 직접구축하면 조금 더 빠르긴한데 취향에 따라 마음대로 해도 되는 부분…
아직 돈내고 써서 엄청 좋아지는 서비스가 없다

  • kustomize
  • gitops
  • githubaction
  • gitlabaction?
  • drone
  • argocd
  • keel

로깅 & 모니터링

hadoop, elastic search, prometheus 거의 이 중 한쪽 생태계와 주변기술 아닐까

구축하는게 튜토리얼대로 하면 금방 할 수 있기도 한데…
서비스에 맞게 튜닝을 하려면 신경쓸게 많다.
생각보다 잘 안되는 편

어떻게 보면 진짜 비핵심적인 부분이기도 해서
진짜 필요한 부분에서는 직접 로그를 DB에 저장하던지 하고
전체적으로는 돈내고 써야하는 분야

sentry, datadog, … 등등 검색하면 많다

클라우드에서 기본 제공해주는 서비스는 대부분 ES, Hadoop 기반이고
커스터마이징이 불편해서 별도로 작업이 많이 필요하다.

[후기] 개발자 이직시 헤드헌터를 통하는 방법

매우 비추천한다

헤드헌터의 서비스(원론적으로)

구직자 대상

  • 이력서 첨삭
  • 연봉 조언
  • 채용정보 제공(기업소개)

채용기업 대상

  • 회사에서 필요한 인재 발굴
    • 경쟁사 직원
    • 구인구직사이트 노출되지 않은 사람
    • 이력서는 완성 돼 있지 않지만 역량이 맞는 사람
  • 채용공고 작성 및 컨설팅
  • 인재 관리 스킬 전수

헤드헌터의 보수

대강 이런 서비스를 제공 해 주고 채용인원 연봉의 5% ~ 10% ~ 20% 정도를 받아가는걸로 알려져 있다.
입사시 사이닝 약간.. 50만원? 5%??
3개월시 10%?? 20%???
6개월 또는 1년시 20%??
계약에 따라 다양하겠지만 최종적으로 정착하면 20%정도로 보면된다

연봉5천짜리면 20%만 받아도 1000만원 원룸소개하는 공인중개사가 들이는 노력과 그 전문성에 대한 보수에 비교 해 보자… 이정도면 변호사보다도 큰 것 같다)

헤드헌터의 스킬

괜찮은 헤드헌터는 HR은 좀 해봤을지 모른다
그런데 그건 신입채용시는 도움이 될지 모르나…
분야별 전문지식이 필요한 경력이직은 좀 얘기가 다르다.

각 기업에서 면접을 보기 전에
* 사전필터도 해 주고
* 인재 발굴도 해 줘야 하는데

요새는 워낙에 정보가 공개 돼 있다 보니 기업과 헤드헌터가 동시에 구직자에게 노출되고 있는 상황이다. 사람인 같은 서비스에서 구직자 검색이 가능한 것도 기업이나 헤더헌터나 마찬가지…
헤드헌터가 기업보다 더 좋은 데이터셋을 보유하고 있지 않다.

헤드헌터가 유용한 경우는
구직자가 먼저 컨텍하는게 아닌 그 반대의 경우다
블로그나 깃헙을 보고 스카웃 제의를 하는 경우
요즘 그런식으로 이직했다는 소식을 간혹 듣긴한다
링크드인도 있겠지만 국내에서는 이거 잘 꾸며놓는 개발자 본 적이 없어서

이력서 첨삭

회사 HR팀에서는 서류통과만 할 정도로 쓰면 된다.
맞춤법 틀리거나 프로젝트 설명을 읽고 무슨 소린지 알 수가 없는 수준만 아니면 패쓰
어차피 세부 검토는 개발팀에서 하는데
사실 여기 통과하는게 힘들다

  • 프로젝트 이름
  • 프로젝트 기간
  • 프로젝트 간략소개
  • 프로젝트에서 담당한 역할
  • 주요 기술스텍 목록
  • 내세울만한점이 있다면(개발시 신경썼던점, 기존 문제상황을 수정했던 부분 등)

헤드헌터가 유용한 경우는
구직자가 먼저 컨텍하는게 아닌 그 반대의 경우다
블로그나 깃헙을 보고 스카웃 제의를 하는 경우
요즘 그런식으로 이직했다는 소식을 간혹 듣긴한다
링크드인도 있겠지만 국내에서는 이거 잘 꾸며놓는 개발자 본 적이 없어서

정 도움이 필요한 경우

페이스북 개발자 모임같은데서 취업스터디 모집하는게 낫다
인맥도 생기고 운좋으면 도움의 손길이 있을수도??

헤드헌터는 여러분 한명한명에게 큰 공을 들이지 않고 관심도 없다
그리고 여러분이 뭘 했는지 제대로 이해하지 못하고 뭐가 중요한지 모른다
개발자 스터디에서 자기가 한 프로젝트에 대해 자세히 설명을 해 주고
함께 요약을 해 보면 훨씬 도움이 될 듯?

헤드헌터가 도움이 되는 경우??

간혹 비밀스럽게 채용이 이뤄지는 경우 공개적으로 이력서를 받지 않는 회사도 있긴 있다…
외국회사나 신규산업진출 등등의 경우..

하지만 보통은 대형 채용사이트와 회사 홈페이지에 함께 올라와 있다.
회사 입장에서도 직접 지원하는걸 더 좋아한다.
결국엔 연봉협상에서도 유리하다는 점

  • 사람인 : 괜찮은 좆소 많음 무난
  • 원티드 : 꽤 트렌디한 채용 서비스.. 사이트는 구린데 왠지 이미지가
  • 잡코리아 : 개인적으로 비선호인데
  • 로켓펀치 : 스타트업 채용
  • 프로그래머스 : 괜찮은 좆소 많음 무난… 탑프로그래머스는 별 도움안됨, 코딩테스트는 쓸만함
  • 인쿠르트 : 개발자는 잘 없지 않나
  • Okky : 구인구직 페이지.. 프리랜서 채용이 많다

남이 나보다 잘 해주지 못한다.

다 직접 해야된다

Querydsl crash – lombok plugin

plugin: 'org.jetbrains.kotlin.plugin.lombok

롬복 x 코틀린 오류

롬복과 코틀린을 함께 쓰려고 하면 오류가 많이 발생한다

컴파일타임에 진행되는 일의 순서 때문에 문제가 발생해서 매우 처리하기 힘들다
lombok, kapt, querydsl, protocol buffer, kotlin

이런저런것들이 컴파일타임에 순서대로 돌아가는데
이 오픈소스들이 애초에 이렇게 같이 쓰는 환경을 고려하고 만든게 아닌지라…
자바에서 코틀린 라이브러리를 쓰는 것 조차 쓸 수는 있는정도니까…
꼭 같이 써야겠다면 그레이들에서 모듈을 분리해서 다른 라이브러리를 쓰듯이 만들어 놔야한다
같은 프로젝트에서 같은모듈에서는 그냥 포기하자

lombok

> Task :server:core:compileKotlin
w: Lombok Kotlin compiler plugin is an experimental feature. See: https://kotlinlang.org/docs/components-stability.html.

Lombok Kotlin compiler plugin is an experimental feature. See: https://kotlinlang.org/docs/components-stability.html.

compileKotlin

java.lang.IllegalStateException: Error during writing proto for descriptor: @javax.annotation.Generated public open class QAdminEntity : com.querydsl.core.types.dsl.EntityPathBase<(kr.steppay.account.domain.model.actor.AdminEntity..kr.steppay.account.domain.model.actor.AdminEntity?)> defined in kr.steppay.account.domain.model.actor in file QAdminEntity.java
Source file: /Users/archmagece/work/steppay/account-service/server/domain/build/generated/source/kapt/main/kr/steppay/account/domain/model/actor/QAdminEntity.java
	at org.jetbrains.kotlin.incremental.JavaClassesTrackerImplKt.convertToProto(JavaClassesTrackerImpl.kt:90)
	at org.jetbrains.kotlin.incremental.JavaClassesTrackerImpl$onCompletedAnalysis$2.invoke(JavaClassesTrackerImpl.kt:68)
	at org.jetbrains.kotlin.incremental.JavaClassesTrackerImpl$onCompletedAnalysis$2.invoke(JavaClassesTrackerImpl.kt:67)
	at org.jetbrains.kotlin.util.PerformanceCounter.time(PerformanceCounter.kt:101)
	at org.jetbrains.kotlin.incremental.JavaClassesTrackerImpl.onCompletedAnalysis(JavaClassesTrackerImpl.kt:67)
	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$invokeExtensionsOnAnalysisComplete(TopDownAnalyzerFacadeForJVM.kt:110)
	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:129)
	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:86)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:540)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:531)
	at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:113)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:531)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:188)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:154)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:169)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:90)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:386)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:110)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:303)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl$rebuild(IncrementalCompilerRunner.kt:99)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:124)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:74)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:607)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:96)
	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659)
	at jdk.internal.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException
	at org.jetbrains.kotlin.lombok.processor.RequiredArgsConstructorProcessor.isFieldRequired(RequiredArgsConstructorProcessor.kt:27)
	at org.jetbrains.kotlin.lombok.processor.RequiredArgsConstructorProcessor.getPropertiesForParameters(RequiredArgsConstructorProcessor.kt:24)
	at org.jetbrains.kotlin.lombok.processor.AbstractConstructorProcessor.contribute(AbstractConstructorProcessor.kt:19)
	at org.jetbrains.kotlin.lombok.LombokSyntheticJavaPartsProvider.computeSyntheticParts(LombokSyntheticJavaPartsProvider.kt:80)
	at org.jetbrains.kotlin.lombok.LombokSyntheticJavaPartsProvider.getSyntheticParts(LombokSyntheticJavaPartsProvider.kt:74)
	at org.jetbrains.kotlin.lombok.LombokSyntheticJavaPartsProvider.generateConstructors(LombokSyntheticJavaPartsProvider.kt:63)
	at org.jetbrains.kotlin.resolve.jvm.CompositeSyntheticJavaPartsProvider.generateConstructors(SyntheticJavaPartsProvider.kt:59)
	at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassMemberScope$constructors$1.invoke(LazyJavaClassMemberScope.kt:102)
	at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassMemberScope$constructors$1.invoke(LazyJavaClassMemberScope.kt:84)
	at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
	at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
	at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor.getConstructors(LazyJavaClassDescriptor.kt:146)
	at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor.getConstructors(LazyJavaClassDescriptor.kt:45)
	at org.jetbrains.kotlin.serialization.DescriptorSerializer.classProto(DescriptorSerializer.kt:115)
	at org.jetbrains.kotlin.incremental.JavaClassesTrackerImplKt.convertToProto(JavaClassesTrackerImpl.kt:88)
	... 43 more


[도서] 소프트웨어 장인

그냥 개발수필에 가깝다
코딩호러의 어쩌고 했던책이 더 재밌었던듯

이 책에서 뭔가 내용이 많이 나오긴 하는데
맞는말이긴 한데 그냥 맞는말뿐이라서 별로 뭔소린지 기억에 남지 않는다

마틴파울러나 GoF같은 유명한 책은 많이 읽은 사람인 것 같다
개발방법론이나 조직에 대해 많이 생각해봤던
10~20년쯤 소프트웨어 개발을 했던 프로그래머
대부분 그정도 근방의 이력을 가진 사람이면 해 봤을법한 생각들

아예 초년생이라면
감명받을 수도 있겠고
뭔소린가 싶을수도 있겠는데
한번 훑어보는게 도움이 되려나

이 책의 태그를 자기계발서로 넣은건…
기술서적이 아니기 때문.

네이버 클라우드 사용후기

네이버 클라우드는
중소 벤처기업에 요금지원을 1~2년씩 해주면서
사용자를 모으고 있는 것 같다

IaC

먼저… 사용하기 매우 싫었다

왜냐면 코드화가 불가능한 인프라라서
https://github.com/NaverCloudPlatform/terraform-provider-ncloud
7개월 째 업데이트가 안 되고 있다
API지원이 미약하거나 테라폼의 중요성을 모르거나 둘 중 하나겠지…
API를 이용해서 직접 코드화를 할까도 생각 해 봤지만…
AWS, GCP, Azure, DOcean, Heroku …. 선택지가 이렇게 많은데 그렇게까지???

비용

그리고 가격만 생각할 것 같으면 통큰아이 서버 쓰는게 낫지 않을까
IDC에 렉 하나 임대해서 서버 들여놓던가

AWS에서 비용 최적화 해서 사용하면 가격이 비슷할 것 같기도 하다
AWS는 BestPractice도 많고 Terraform코드화가 쉬워서

코드화가 가능하면 안쓰는 인프라를 그 때 그 때 껐다가 다시 켜고 재설정이 가능해서

설치편의성

ElasticSearch를 설치했는데
ManagerNode가 두개인데
별개로 접할수가 없어서 찾다보니
LoadBalancer를 설치해야한다고??? 18000원이라고????

가입 편의성

금융클라우드는 Console에 VPN없이 접속이 안된다. 경고는 따로 없고 타임아웃

VPN을 통해야 접속이 가능한데 동시접속이 안된다

VPN을 만들려면 SubAccount가 필요하다
2차인증이 필수라길래 구글 OTP를 등록했더니
VPN을 등록하려면 이메일 인증을 해야한다고 한다
이메일 안오는데?????
스팸인가?? 네이버 메일로만 전송을 해주나???
SubAccount를 다시 생성해볼까??
네이버 서버 병신이네!!! 라고 생각하다가 문득
아니!!
구글OTP를 등록하고 나면 이메일 인증을 할 수 없다.
설마했지만 맞았다.
병신은 서버가 아니라 소프트웨어였다
클라우드도 기획자가 있나? 기획자가 보내준거 리뷰 후에 변경안하고 바로 개발 해 버나?
개발자가 이따위로 했을리가…
이따위로 할 수는 있긴한데 그대로 놔뒀을리가…
구글OTP를 안되는거 지웠으면 지웠지…

~

쓰고 나니까 좋은 소리가 하나도 없네
잘좀 하시라구요

  • 점점 나아지겠지만 아직은 아니다
  • 네이버클라우드 직원들 고생좀 하겠다

SpringSecurity MockMvc테스트시 발생

MockMvc 설정

//            val delegatingFilterProxy = DelegatingFilterProxy()
//            delegatingFilterProxy.init(MockFilterConfig(context.servletContext, BeanIds.SPRING_SECURITY_FILTER_CHAIN))
            this.mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
//                .apply<DefaultMockMvcBuilder>(springSecurity())
//                .addFilters<DefaultMockMvcBuilder>(delegatingFilterProxy)
                .addFilters<DefaultMockMvcBuilder>(CharacterEncodingFilter("UTF-8", true))
                .alwaysDo<DefaultMockMvcBuilder>(MockMvcResultHandlers.print())
                .build()

test 설정

@WithMockKeycloakAuth(~~~)
@WithUserDetails("user1")
@Test
fun test() {
}

상태? 문제?

  1. Header인증을 사용하는 경우 no header -> jwt같은건 직접 header에 넣어줘야한다
    그렇다면 @Withannotation을 사용하기 힘들다는 뜻
  2. controller에 parameter로 Authentication을 받는경우 null – null… 어떻게 하지?
    SecurityContextHolder, TestSecurityContextHolder엔 들어있다
    WithSecurityContextTestExecutionListener: TestExecutionListener은 동작된다.
    principal = TestSecurityContextHolder.getContext()
  3. ???또 뭐가 있었던가

서비스 규모에 따른 인프라 결정

개요

경험이 없는 팀은 서비스 초반에 인프라 결정장애를 겪는다

좋아보이는거 다 쓰면 정말 끝도 없다 이슈해결도 안되고

잘 하는 인프라가 있는 경우 상관없지만
아닌 경우에 따를 수 있는 규칙

쿠버네티스는 관련인프라 필요한게 너무 많다

인프라 결정 기준

  • 개발인원에 따라 1~5인, 10인, 100인…
  • 서비스 사용자 규모 100명, 1000명
  • 인프라 비용
  • 무정전 서비스가 필요

다양한 요건이 있는데 인프라 비용에 따라 결정하는게 속편하고 빠르다.

기준도 명확하고
기준을 넘어서는 경우 다음 단계로 올라가기 위한 작업을 하면 된다

결정이고 뭐고 필수사항

  • Container – 보통 Docker
  • IaC – 인프라 코드화
  • Git – github을 많이 쓰는데 gitlab.com은 무료에 빠르다
  • 로깅 – Sentry

인프라 월비용에 따른 결정

간단한 웹서비스의 경우

무료 ~ 30만원

헤로쿠 heroku.com

30만원 ~ 100만원

서서히 기술욕심이 생기는 단계
매니지드 k8s를 사용해볼만하다
헤로쿠는 국내서버 제공이 안되고 느리기도 하니까

GCP, AWS, AZURE, DigitalOcean 매니지드 k8s

금지항목

  • EB(ElasticBeanstalk)
  • ECS
  • GoogleAppEngine

위 항목은 속터지는 것에 비해 편리하지 않다

CloudFunctions, Lambda 등은 생각보다 설계 자체가 어렵고 디버깅도 어렵고 관리도 힘들다
연습용 으로 한두개 추가하기는 괜찮느데 초기 서비스에는 오히려 적합하지 않다

100만원 ~ 1000만원

서버 비용을 걱정하기 시작해야 할 단계

중소 클라우드 업체랑 계약 잘 하면
몇달정도 공짜로 쓰게 해준다
다 쓰고나서 눌러앉아도 되고 옮겨도 된다
어차피 k8s는 다 있으니까 상관없다

네이버 클라우드같은 경우는 IaC가 잘 안되는 문제가 있다.
많이 쓰는 TerraForm 지원이 거의 없다.

서버 API는 잘 돼 있긴한가 모르겠다

1000만원 ~

멀티클라우드

[도서] 도메인 주도 설계로 시작하는 마이크로서비스 개발, 핵심 개념과 패턴, 설계, 구현으로 배우는 DDD와 MSA

깊은 지식을 얻는다기보다는 그냥 관련기술을 훑어보기 좋다

DDD 이론서 보고 어떻게 할지 모르겠는 사람들을 위한 책이라고 봐야하려나

기존에 좀 하고 있던 사람들에게는 별로 얻을건 없고

다른 사람도 같은 고민을 하고 있었구나 하는걸 알 수 있다

주요내용

아키텍처

  • 레이어드 아키텍처
  • 헥사고날 아키텍처
  • 클린 아키텍처

https://engineering-skcc.github.io/microservice%20inner%20achitecture/inner-architecture-2/

이벤트 스토밍

도메인 이벤트Orange발생한 사건 pp로 표현
커맨드Blue도메인 이벤트 트리거
외부시스템Pink도메인 이벤트가 호출하거나 관계가 있는 레거시 또는 외부 시스템
액터Yellow개인 또는 조직의 역할
애그리거트Yellow도메인 이ㄴ트와 커맨드가 처리하는 데이터
상태가 변경되는 데이터
정책Lilac이벤트 조건에 따라 진행되는 결정
when, then
읽기모델Green도메인 이벤트 엑터에게 제공되는 데이터
사용자 인터페이스White스케치 형태의 화면 레이아웃
핫스팟Purple의문, 질문, 미결정 사항

jhipster

추천도서

아키텍처

  • 마이크로 서비스 패턴
  • 클린 아키텍처
  • 엔터프라이즈 애플리케이션 아키텍처 패턴

개발 프로세스

  • 소프트웨어 장인

설계

  • UML 패턴의 적용
  • 도메인 주도 설계, 위키북스 2011
  • 도메인 주도 설계 핵심 이론, 에이콘 2017
  • 도메인 주도 설계 철저 입문, 위키북스 2020
  • Introducing Event Storming, Leanpub 2019

개발영역

  • 자바 ORM 표준 JPA 프로그래밍, 에이콘 2015

Keycloak 인증 솔루션 선택 – 그리고 ext개발

관련기술 모음

Keycloak vs CAS 선택은

국내에서는 Springboot을 많이 쓰다보니 CAS를 많이 쓸 것 같지만
사용의 난해성 때문에 Keycloak이 더 많이 사용된다
Keycloak에서 커스터마이징 해서 추가기능은 구현할 수 있지만 약간의 문제가 있다
– 별도 인스턴스를 띄워야한다는 문제
– 기본지원되는 형태로 사용해야하는 문제
극한의 커스터마이징을 하려면… 그냥 따로 만드는게 낫다
서비스 초반에는 있는 그대로 쓰자….

CAS는 뭔가 실행하는 것도 매우 힘들고 라이브러리처럼 사용해야하는데 그것도 힘들다. 도큐먼트도 없고… 그냥 인증스펙 구현을 어떻게 했는지 참고하는 코드로 쓰기는 좋다
https://memo.polypia.net/archives/3783

간단하게 결론을 내면
뭘 쓰건 기본기능 그대로 쓸게 아니라면 사용이 쉽지는 않다.

초반에는 서비스를 오픈소스에 맞춰서 쓰자

Keycloak 사용후기

개인적인 경험으로 봤을 때 keycloak이 CAS보다 간단하다.
그냥 기본기능을 가지고 사용하기도 쉽고
추가기능 구현한달정도 보다보니 구조파악이 되고 좀 할만해졌다

JBoss기반으로 만들어져서 Spring생태계에 익숙한 개발자가 접근하기 쉽지는 않다
jas-rx 기반 resteasy, wildfly 서버, jboss의존성 관리 등등..
그냥 도큐먼트만 보고 하려면 rest api 호출하는것도 쉽지가 않다.(공식문서에 주소를 엉터리로 적어놔서 ㅋ)
keycloak 소스코드와 인터넷 질문답변을 잘 읽어봐야한다
그리고 샘플 확장코드들

  • https://github.com/keycloak
  • https://github.com/ScriptonBasestar-io/keycloak-providers
  • https://github.com/thomasdarimont/keycloak-user-storage-provider-demo
  • https://www.baeldung.com/java-keycloak-custom-user-providers
  • https://github.com/thomasdarimont/keycloak-extension-playground
  • https://github.com/zonaut/keycloak-extensions

Keycloak 문제점? 헷갈리는 포인트

Keycloak 설명

오픈소스
회원관리 oauth2-oidc, saml 서버기능 지원
외부 Oauth 소셜로그인 지원(구글,페북,인스타..등)

헷갈리는 점

이해를 못해서 헷갈리는 점 말고 설계가 잘못됐다고 생각하는 부분

import가 아니고 partial import

json으로 export하고 import 한다고 하면 서버 설정전체를 집어넣고 내보내는거라고 생각하기 쉬운데
지원되는 항목이 정해져 있다
추가기능으로 설치한것들은 지원이 안되는 것 같다

rabbitmq EventListener를 추가했더니 export는되는데 import가 안된다

기본 client

realm을 처음 생성할 때 clients가 생성된다

  • {realm_name}-realm 이건 렐ㅁ을 생성할 때 마다 master 렒에 추가된다
  • master-realm은 master 렒의 Clients에 추가된다
  • account 계정관리 권한 이걸 지우면 로그인도 안된다 https://keycloak.com/auth/realms/master/account/
  • account-console 콘솔로그인 권한
  • account-cli
  • broker 소셜로그인 권한인가
  • security-admin-console

기본 옵션을 클라이언트에 달아놓은게 맘에 안들어.. 수정/삭제 버튼도 달려있다.

role

기본 client의 문제가 이어진다

기본 client는 고유 권한을 가지고 있다.

keycloak에서는 previlege를 별도로 관리하지 않아서
고유 client가 role이라는 이름으로 previlege(role)을 들고있다
소스에 보니까 string으로 선언이 돼 있어서 이름만 같으면 되나 싶어서
같은 이름 생성 해 봤는데… 이름같아서 헷갈리기만 하도 안된다

전체에서 관리되는 role과 client에서만 관리되는 role 그리고 기본client의 role이 별도로 존재한다고 봐야할까

새로운 client에 previlege를 부여하려면 composite roles를 선택해서 기본 client의 previlege를 associate 해야한다

그냥 잘못 만든 점

Events – Evnets Config에서

EventListeners를 설정하고 evnet종류를 지정할 수 있는데

EventListener가 한개일 때는 괜찮은데 여러개일 때
리스너 종류에 따라 다른 이벤트 설정을 못 하게 돼 있다.

ex) jboss-logging이 기본인데 이건 전부 수신하고
email로는 회원가입만 보내고 싶다… 라면..?? 이거 안된다.

User – Role – Previlege

구분이 좀 됐으면

아쉬운 점

플러그인 참여가 오픈되어있지 않다

사용자가 꽤 많은 것 같은데 기본지원되는 소셜로그인 말곤 따로 만들어야된다
커뮤니티 좀 활성화 돼 있으면 사람들이 알아서 만들고 할텐데

과도한 커스터마이징 미지원

버전이 14까지 올라갔는데 지원이 안되고 있네
좀 시도해볼만하지 않나
oauth말고 그냥 서비스 특화된 방식

커스텀 필드

되긴되는데 좀 불편

주소 문제

https://auth.service.com
/ 주소는 무슨 홍보페이지같은거고
/auth가 실제 서비스 주소가 된다
/auth/realms/master 처럼 주소가 나온다

기본 서비스 clients랑 같은 문제인데… master realm, 서비스 어카운트 등은 일반사용자와 다른 테이블에 다른 차원으로 관리되는게 좋은데 개인적으로는

각 렒별로 주소를 별도로 할당하고싶기도 한데 그것도 안된다
누가봐도 keycloak를 쓰고 있다는걸 알 수 있는 상태로 오픈해야한다

reverse proxy로 처리하면 할 수는 있을 것 같은데 좀 봐야겠다

좆같은 캐시

infinispan과 jpa 두 계층으로 데이터를 저장하는데
캐시를 굉장히 무겁게 사용하고 있는 것 같다
솔직히 잘 모르겠다. 그냥 좆같다
어디서 뭐가 저장 돼 있는지 따라갈수가 없어서 뭘 수정 할 수도 없다

RestEasy

이런 그지같은 rest api client는 스프링 web client 말고는 없다

호출 수백번 반복

회원가입할 때 저장을 수십번 하는 것 같은데
디비에 필드단위로 정규화한 데이터를 저장하는 병신짓은 아무도 안하는게 당연한데
그런식으로 저장하고 있는거 아닐까

성능

뭐 이따윈지

DDD

DDD를 잘 쓰려고 노력한 것 같은데
잘 하지는 못했다

hmm

초기서비스용으로 있는그대로 쓰면 괜찮다
학습용으로 좋다
개인서버용 정도로 쓰기 좋다