Spring Boot Actuator readiness, liveness probes on k8s

이미지
Spring Boot 를 사용하여 서버 어플리케이션을 개발하고 Kubernetes 상에서 운영할 때 Container 의 상태를 확인하고 복구가 불가능한 경우 재시작 시켜야 되는지 알 필요가 있다. 또한 Container 가 트래픽을 받아들일 준비가 되었는지 상태를 알아야한다. 이때 각각 liveness, readiness probes 를 사용한다. 아래와 같이 Kubernetes deployment 에 liveness 와 readiness probes 를 설정한다. initialDelaySeconds 는 Container 가 실행되고 90초 이후에 설정된 path 에 Get 요청을 통해서 정상상태를 확인한다. 200 ~ 399 status code 를 5초이내에 응답 받으면 성공으로 확인한다. periodSeconds 는 10초 주기로 확인한다. 연속해서 3번 비정상 응답을 받을 경우 liveness 는 실패로 돌아가고 Kubelet 은 Container 를 재시작시킨다. 이번엔 Spring Boot 어플리케이션을 보자. gradle 을 사용할 때 아래와 같이 의존성을 추가한다. 그리고 application.yaml 에 아래와 같이 설정한다. 유의해야할 점은 exposure.include 에 * 를 쓰게되면 불필요한 정보가 모두 노출되어 보안에 취약해진다. 예를 들어, heapdump 또는 shutdown 같은 기능을 노출하게 되면 외부에서 공격점이 될 수 있다. /actuator path 요청시 아래와 같이 응답을 받는다.  exposure 에 health, info 만 설정해서 두가지만 확인할 수 있다. /actuator/health 를 확인해보자. endponint.health.probes.enabled=true 로 설정해서 liveness, readiness 를 지원한다. /actuator/health/liveness 와 /actuator/health/readiness 를 확인해보자.  spring boot application 에...

Install and Run Kafka on my M1 Macbook

이미지
 M1 맥북 로컬에 카프카를 설치하는 방법은 두가지가 있다. binary 로 다운받아서 설치하는 방법과 간단한 homebrew 를 통해서 설치하는 방법이 있다. homebrew 로 진행해보자. m1 의 homebrew 통한 설치 경로는 아래와 같다. - 바이나리와 스크립트는 /opt/homebrew/bin - Kafka 설정들은 /opt/homebrew/etc/kafka - Zookeeper 설정은 /opt/homebrew/etc/zookeeper - log.dirs config (the location for Kafka data) 는 /opt/homebrew/var/lib/kafka-logs 1. homebrew 설치 1 /bin/bash -c " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh ) " 2. kafka 설치 brew install kafka 3. zookeeper 실행 zookeeper-server-start /opt/homebrew/etc/zookeeper/zoo.cfg 4. kafka 실행 kafka-server-start /opt/homebrew/etc/kafka/server/properties Zookeeper 없이 실행하기 - Kraft 1. Kafka UUID 생성 kafka-storage random-uuid # 76BLQI7sT_ql1mBfKsOk9Q 2. 포맷팅 kafka-storage format -t <uuid> -c /opt/homebrew/etc/kafka/kraft/server.properties # Formatting /opt/homebrew/var/lib/kraft-combined-logs with metadata.version 3.4-IVO. 3. kafka 실행 kafka-server-start /opt/homebrew/etc/kafka/kraft/server.properties ...

How to prevent replay attack?

이미지
Replay Attack 이란? replay attack 은 공격자가 유효한 네트워크 데이터 패킷을 가로채서 이후에 다시 사용하는 네트워크 공격의 유형이다. 데이터를 다시 전송하여 시스템이 정상적인 데이터로 처리하도록 한다. replay attack 은 실제로 정상적인 요청으로 보이기 때문에 탐지가 어렵다. 덧붙여 원래 전송이 암호환된 경우에도 성공할 수 있다. replay attack 은 반복적인 요청을 통해 시스템에 과부하를 줄 수 있다. 이로 인해 시스템의 정상적인 작동을 방해할 수 있다. 공격자는 그림과 같이 데이터 전송이 시작될 때까지 기다린다. 이후에 통신 채널을 스니핑하여 데이터를 추출한다. 공격자는 데이터를 입수하여 목적에 따라 데이터를 수정해서 다시 사용할 수도 있다. 수신자는 변조된 데이터를 받았지만 정상적인 데이터로 취급한다. 대표적인 4가지 유형이 있다. 네트워크, 무선, 세션, HTTP 가 있다. 네트워크 replay attack 은 공격자가 네트워크 트래픽을 가로챈 후 나중에 다시 전송한다. Wireshark 또는 tcpdump 와 같은 도구를 사용한다. 무선 replay attack 도 동일하게 무선 통신을 가로챈 다음 다시 전송한다. 세션 replay attack 은 두 당사자 간의 세션을 가로챕니다. HTTP replay attack 은 공격자가 HTTP 요청과 응답을 캡처하여 HTTP replay attack을 실행한다. 실제 예시 앨리스가 웹을 사용하여 온라인 뱅킹 계좌에 로그인하려고 한다고 가정한다. 앨리스가 로그인 자격 증명을 입력하고 제출 버튼을 클릭하면 로그인 요청이 인터넷을 통해 은행 서버로 전송된다. 공격자 밥은 네트워크를 모니터링하여 로그인 요청이 전송되는 것을 캡처한다. 그런 다음 밥은 앨리스가 계정에서 로그아웃할 때까지 기다렸다가 캡처한 로그인 요청을 은행 서버로 재전송한다. 로그인 요청이 유효하므로 서버는 이를 수락하고 밥에게 앨리스의 계정에 대한 액세스 권한을 부여한다. 어떻게 하면 Replay Attack...

About Websocket minimize data size and data transfer cost on cloud

이미지
웹소켓은 클라이언트와 서버간의 양방향으로 상호작용할 수 있게 만들어준다. 주로 채팅, 게임, 금융 거래 시스템 등 실시간 데이터 처리를 위해서 사용한다. 웹소켓을 사용하지 않고 롱폴링과 같은 방법을 사용할 수 있지만, 매 데이터 교환마다 새로운 요청을 보내야 한다. 웹소켓은 한번의 커넥션으로 지속해서 통신할 수 있어서 낮은 latency 를 보장한다. 따라서, 더 빠르고 유려한 사용자 경험을 제공할 수 있다. 내가 운영하는 서비스에서 웹소켓을 사용하고 있다고 가정해보자. 그리고 추가로 사용자가 접속할 때 항상 웹소켓을 사용해야 한다. 예를 들어, 주식 시장이나 코인 시장의 가격을 실시간으로 확인하거나, 교통의 흐름을 추적한다고 가정해보자. 실시간으로 제공해야 하는 제공해야 하는 데이터가 많아진다. 사용자가 많아질수록 또한 제공해야 하는 데이터가 많아진다. AWS와 같은 클라우드를 사용하여 서비스를 운영하는 상황일 때 데이터의 양이 많아질 경우 비용 증가로 이어지게 된다. AWS Data Transfer Cost 가 부과되는 방법은 다양하지만 이번 경우에서는 AWS 환경에서 Internet 환경으로 data 가 전송되는 구간에 대해서 정리해보겠다. 2023-03-12 기준 서울 region 에서 인터넷으로 데이터 송신 비용이다. 처음 100GB 전송은 무료이며 이후 부터 전송량 별 비용이 감소한다. 0 ~ 100GB 무료 100GB ~ 10340GB  0.126USD/GB 10340GB ~ 41060GB 0.122UDS/GB ... 생략 이렇게 산정되는데 10TB를 꽉 사용했다는 가정하에 가격은 1302.84 USD 이다.  2023-03-12 기준 1달러 환율은 1,320.64원이다.  1720582.6176 원으로 172만 5백원이다. 무시할 수 있는 비용이 아니다. 어떻게 해당 비용을 줄일 수 있을까?  Data Serialization json 일반적으로 WebSocket 으로 데이터를 교환할 때 흔히 사용한다. text...

About UTF-8, Base64

이미지
컴퓨터는 항상 비트를 다룬다 그리고 비트를 사용해 수와 같은 대상을 표현한다. https://infondgndg91.blogspot.com/2023/02/about-binary-number.html  그렇다면 문자나 키보드에 있는 다른 기호는 어떻게 표현할까? ASCII(American Standard Code for Information Interchange) 키보드에 있는 모든 기호를 7bit 를 할당했다. 예를 들어 65 는 대문자 A 66은 대문자 B를 표현한다. 아래 링크에서 확인할 수 있다. https://www.asciitable.com/ 위와 같이 글자를 출력하는 데 쓰이지 않고 장치를 제어하기 위해 쓰이는 control character 가 있다. 이 중 상당수는 통신 제어를 위한 문자다. ACK(수신확인) '메세지를 받았음' 이고, NAK(반수신확인)는 '메세지를 받지 못했음'을 의미한다. 유니코드(Unicode)  아스키는 영어를 표현하는 데 필요한 모든 문자를 포함하고 있어서 상당 기간 표준 역할을 했다. 초기 컴퓨터는 미국산 혹은 영국산이었기 때문이다. 컴퓨터가 널리 쓰이게 되면서, 이외의 언어를 지원해야 했다. 국제 표준화 기구인 ISO(International Standard Organization) 은 ISO-646, ISO-8859 를 도입했다. 기본적으로 아스키를 확장해 유럽 언어에 필요한 액센트 기호나 그 밖의 발음 구별 기호를 추가했다. 그리고 일본 산업 표준  위원회는 JIS(Japanese Industrial Standards) 일본 문자 표현을 위해서 JIS X 0201 을 만들었다. 또한 중국어, 아랍어, 한국어(KS C 5601) 등 표준도 생겼다.   이렇게 많은 표준이 존재한 이유는 비트가 지금보다 더 비쌌다. 그래서 최대한 문자를 7비트나 8비트에 욱여넣었다. 비트가격이 떨어지면서 유니코드라는 표준이 생겼다. 문자에 16비트 코드를 부여했다. 16비트면 지구상의 모든 문자...

About Binary Number

이미지
이번 글에서는 기초로 돌아가는 시간을 가진다. 컴퓨터에서 정수와 실수를 어떻게 다루고 있는지에 대해서 정리하려고 한다. 우리는 일상생활에서는 10진법을 사용한다. 아무래도 손가락이 10개라서 이지 않을까?  하지만 컴퓨터에서는 2진법을 사용한다. 컴퓨터는 10진법을 이해하지 못한다.  컴퓨터가 사용하는 2진법 컴퓨터는 손가락이 2개만 있다.  컴퓨터는 전압을 사용하여 동작한다. data 가 있을 경우 전압을 올리고 없을 경우 내린다. on / off 로 부를 수 있는데 이러한 과정을 계속해서 반복한다. 전압을 올린 곳은 1 로 표현할 수 있고, 전압이 없을 경우 0으로 표현한다. 이러한 data 를 연결할 경우 101101 과 같은 data 가 된다. 이러한 data 0 또는 1 을 bit 라고 부른다. 1bit 는 0 또는 1 두가지 경우를 나타낼 수 있다. 1bit = 0, 1 = pow(2, 1) = 0 ~ 1 2bit = 00, 01, 10, 11 = pow(2,2) = 0 ~ 3 4bit = 0000, 0001, 0010, ... 1111 = pow(2,4) = 0 ~ 15 8bit = 0000 0000, .... 1111 1111 = pow(2,8) = 0 ~ 255 bit 가 8개 8bits 는 1 byte 가 된다. 8bits 의 절반인 4bit 를 nibble 이라고 부른다. 컴퓨터가 저장하는 최소단위가 byte 이다. 8 bits = 2 nibble = 1 byte 이다. nibble 은 4bits 이다. nibble  단위가 16진수의 단위가 된다.  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, a, b, c, d, e, f 1111 1111 은 10진수로 15 15 이고 16진수로 표현하자면 f f 가 된다. 0xFF 가 된다. 0xFF 는 1 byte 가 된다. 정수 2진 표현 Kotlin 을 기준으로 Int 는 4 bytes 로 32 bits 이다. 양의 정수 5028 을 2진...

Time Business Logic Testing on Spring (Kotlin, Java)

이미지
올해에 너무 글쓰는 것을 소홀히 했던것을 반성하며 남은 한 달 동안 글을 몇 개라도 조금 써보려고한다! Java, Kotlin 기반 Spring 프레임워크 환경에서 개발을 하다보면 시간과 관련된 로직이 필요할 수 있다. 이 때 어떻게 해결하면 좋을 지 테스트 코드는 어떻게 구성하면 좋을지 정리하려고 한다. 예를 들어, 특정 기간동안만 액션이 가능한 요구사항이 있다고 가정하자. 해당 기간이 시작하기전에 액션을 진행하지 못하도록 막아야 되고, 기간인 경우 가능하도록 그리고 기간이 끝났을 때 더이상 액션이 불가능하도록 막아야 한다. 이 예제를 바탕으로 간단한 샘플 코드를 정리해보았다. - Kotlin - Spring Boot 2.7.5 - Junit 5 우선 아래와 같이 zoneId 를 인자로 받는 now 함수를 작성하였다. CHANGEABLE_CLOKC 이 null 이 아닐경우 해당 Clock 을 기준으로 LocalDateTime 인스턴스를 생성한다. 그리고 now 를 테스트하기 위한 코드. CHANGEABLE_CLOCK 이 null 인 경우와 null 이 아닌 경우 두 가지 테스트 케이스이다. null 인경우에는 zoneId 에 따라서 인스턴스를 생성하기 때문에 빈 인자인 경우 UTC 기준, Kst ZoneId 제공시 kst 시간 인스턴스를 생성하여 9시간 차이를 확인하는 코드이다. 두번 째는 Clock 을 2025 년 1월 1일로 설정하여 now 함수 호출 시 CHANGEABLE_CLOCK 기준으로 인스턴스를 생성하게 되어있다. 자 그렇다면 기간과 관련된 로직과 해당 로직을 테스트하는 코드를 작성해보자. 아래와 같이 property 에서 기간을 주입받는 Service 를 test code 를 작성해보자. ReflectionTestUtils 를 통해서 Mocking 하는 service 에 기간을 주입한다. 그리고 CHANGEABLE_CLOCK 을 통해서 now() 함수가 기간에 속할 때와 아닐 때로 지정하여서 올바른 값을 반환하는지 검증한다. 또 다른 방법중 하...