본문 바로가기

분류 전체보기

(35)
[Jenkins] Timeout의 파이프라인 무한 루프 방어 "어? 어제 퇴근할 때 걸어놓은 배포가 오늘 아침까지 안 끝나고 계속 돌아가고 있네?" CI/CD 인프라를 운영하다 보면 누구나 한 번쯤 마주치게 되는 소름 돋는 상황입니다. 쉘 스크립트 안에 잘못 작성된 while(true) 무한 루프 버그, 혹은 외부 API 서버가 죽어서 응답을 주지 않아 무한 대기(Hang)에 빠지는 경우 등 원인은 다양합니다. 문제는 이렇게 '에러를 뿜으며 실패(Failure)하지도 않고, 그렇다고 성공(Success)하지도 않은 채 영원히 멈춰있는 좀비(Zombie) 빌드'들이 젠킨스의 가장 큰 적이라는 점입니다. 이번 글에서는 소중한 젠킨스의 워커(Worker) 자원을 갉아먹는 좀비 빌드들을 제거하는 'Timeout(타임아웃) 제어를 통한 파이프라인 무한 대기 방어 기술'에 ..
[Jenkins] Maven Gradle 빌드 캐시 최적화 빌드 시간 10배 단축의 비밀 "코드는 고작 한 줄 수정했는데, 젠킨스 빌드 시간은 무려 15분이나 걸려?"자바(Java/Spring Boot) 프로젝트나 Node.js 프로젝트의 파이프라인을 운영하다 보면 가장 많이 듣게 되는 불만 중 하나입니다. 코드를 컴파일하고 테스트하는 데 걸리는 시간은 1분도 안 되지만, 스프링 프레임워크와 수많은 서드파티 라이브러리(.jar 파일들)를 Maven Central이나 원격 저장소에서 다운로드하는 데 14분이 걸리기 때문입니다. 특히 앞서 우리가 칭송했던 'Docker Agent(1회용 멸균 빌드 환경)'를 사용할 경우, 이 문제는 최악의 형태로 발현됩니다. 컨테이너가 뜰 때마다 백지상태이므로 매 빌드마다 수백 메가바이트의 라이브러리를 인터넷에서 새로 받아와야 하니까요. 이번 글에서는 인프라 병..
[Spring Boot] Redis 캐싱(Caching)을 이용하여 응답 속도 단축하기 스타트업이 처음 런칭했을 때는 유저가 적어 데이터베이스(RDB) 하나만으로도 충분히 서비스가 잘 돌아갑니다. 하지만 마케팅이 대박 나서 '초당 1만 건'의 요청이 쏟아지기 시작하면 상황은 달라집니다. 여러분이 앞선 에서 HikariCP 커넥션 풀을 아무리 완벽하게 튜닝해 놓았더라도, 물리적인 디스크(Disk)를 긁어서 데이터를 읽어오는 관계형 데이터베이스(MySQL, Oracle)는 태생적으로 속도의 한계가 있습니다. 특히 '쇼핑몰 메인 페이지의 배너 이미지 목록'이나 '오늘의 인기 검색어'처럼 수많은 유저가 똑같이 조회하지만, 데이터는 하루에 한두 번만 변하는 정보를 매번 느린 디스크 DB까지 내려가서 읽어오는 것은 엄청난 리소스 낭비입니다.이를 해결하기 위해 백엔드 진영이 도입한 궁극의 마법, "디스..
[Spring Boot] QueryDSL 입문 / 타입 세이프(Type safe) 동적 쿼리 Spring Data JPA의 Query Method와 @Query는 훌륭했지만, 실무의 거친 요구사항을 만나면 한계가 명확하게 드러납니다. 쇼핑몰의 상품 검색창을 생각해 봅시다. 사용자는 '상품명'만 검색할 수도 있고, '가격 범위'만 필터링할 수도 있으며, '카테고리'와 '브랜드'를 동시에 선택할 수도 있습니다.즉, 조건이 있을 수도 있고 없을 수도 있는 '동적 쿼리(Dynamic Query)'가 필요합니다. 과거 MyBatis 시절에는 XML 파일에 같은 태그를 수십 개 도배하여 쿼리 문자열(String)을 조립했습니다. JPA @Query에서 문자열로 동적 쿼리를 짜다 보면 띄어쓰기 하나 잘못해서 서버가 켜진 뒤 고객이 검색 버튼을 누르는 순간 에러가 터집니다(런타임 에러). 자바 코드로 쿼리..
[Spring Boot] Spring Data JPA 쿼리메서드(QueryMethod)로 검색과 페이징을 구현하기 과거 JPA(Hibernate)만 순수하게 쓰던 시절에는 개발자가 직접 EntityManager를 불러와서 em.persist(), em.find() 같은 코드를 짰습니다. 이 정도만 해도 SQL을 안 짜서 행복했지만, 스프링 진영은 여기서 만족하지 않았습니다. "아니, 저장하고 찾고 삭제하는 CRUD 코드는 전 세계 모든 프로젝트가 다 똑같은데, 개발자가 왜 굳이 그 코드를 또 짜야 해? 우리가 다 만들어 줄게!"라는 발상에서 만들어진것이 바로 Spring Data JPA입니다. 이제 우리는 그저 JpaRepository라는 인터페이스 하나를 상속받는 것만으로 수십 개의 기본 쿼리 기능이 하늘에서 뚝 떨어지는 기적을 맛봅니다. 하지만 진짜 마법은 지금부터입니다. 만약 "나이가 20살 이상이고 이름이 '..
[Jenkins] Jenkins 백업 스크립트 복구 데브옵스(DevOps) 엔지니어의 가장 큰 덕목은 배포 속도를 빠르게 만드는 것도 중요하지만, '최악의 장애 상황에서도 인프라를 신속하게 복구(Disaster Recovery)해 내는 것'입니다. 수십 개의 프로젝트 파이프라인과 플러그인, 계정 정보, 복잡한 인증키(Credentials)들이 세팅된 젠킨스 서버의 하드디스크가 어느 날 갑자기 물리적 장애로 뻗어버린다면 어떻게 될까요? 백업이 없다면 전사의 배포 프로세스는 수일 동안 올스톱되며 당신은 시말서를 피할 수 없을 것입니다.1. 무엇을 백업하고, 무엇을 버릴 것인가? (용량 최적화)초보 인프라 관리자들은 "백업? 그냥 /var/jenkins_home 디렉토리 전체를 통째로 압축해서 보관하면 되잖아?"라고 생각합니다. 이는 매우 무식하고 위험한 발상..
[Jenkins] 쿠버네티스(KubernetesK8s) 완벽 연동 무중단 배포 자동화 앞선 를 통해 애플리케이션 코드를 아름다운 도커 이미지(Docker Image)로 굽고 레지스트리에 푸시(Push)하는 것까지 성공하셨습니다. 이제 남은 과제는 단 하나, "이 이미지를 실서비스가 돌아가고 있는 운영 서버들에 띄워서 고객들에게 선보이는 것"입니다.현대의 대규모 인프라에서는 이 서버들을 지휘하기 위해 Kubernetes(쿠버네티스, 이하 K8s)라는 막강한 오케스트레이션 툴을 사용합니다. 젠킨스가 빌드마스터라면, K8s는 함대 사령관입니다. 이번에는 젠킨스가 원격 K8s 클러스터에 접속하여 새로운 버전의 이미지를 무중단(Rolling Update)으로 교체하라고 명령을 내리는 완벽한 배포 연동 전략에 대하여 다뤄보겠습니다.1. Kubeconfig 보안과 원격 접속 인증우리가 터미널에서 ku..
[Spring Boot] JPAHibernate 기초 객체와 관계형 DB의 패러다임 불일치를 부수다 과거의 자바(Java) 백엔드 개발자들은 게시판 하나를 만들려 해도 INSERT INTO board VALUES..., SELECT * FROM board WHERE... 등 길고 지루한 SQL 쿼리문을 수백 줄씩 타이핑해야 했습니다. 만약 중간에 DB 테이블에 컬럼이 하나라도 추가되면, 그 수백 줄의 쿼리문을 일일이 다 찾아다니며 수정하는 끔찍한 '노가다'의 연속이었죠. 게다가 객체 지향 언어인 자바(Java)와 관계형 데이터베이스(RDB)는 태생적으로 사상(Paradigm)이 너무나도 달랐습니다. 자바는 '상속'과 '참조'를 사랑하지만, DB는 그냥 2차원 표(Table)일 뿐이니까요. 그런데 개발자가 순수하게 '자바 객체'만 다루면 알아서 뒤에서 SQL을 짜주고 DB에 넣어주는 마법의 기술이 등장했..
[Spring Boot] 의존성 주입DI과 IoC 컨테이너 객체의 생성 소멸 자동화 우리가 자바(Java) 학원에서 처음 프로그래밍을 배울 때, 어떤 클래스의 기능을 사용하려면 무조건 new 키워드를 사용해 메모리에 객체를 찍어내야 한다고 배웠습니다. 예를 들어 UserService에서 UserRepository가 필요하면 UserRepository repository = new UserRepository(); 처럼 직접 생성했습니다. 하지만 실무 스프링 부트(Spring Boot) 프로젝트 코드를 아무리 뒤져봐도 new 키워드를 찾아보기는 하늘의 별 따기입니다. 개발자가 객체를 직접 만들지 않는데 도대체 프로그램이 어떻게 굴러가는 걸까요? 이 거대한 미스터리를 푸는 열쇠이자, 전 세계 수많은 자바 개발자들을 스프링의 노예(?)로 만들어버린 가장 위대하고 핵심적인 철학이 바로 IoC(I..
[Spring Boot] 서버 로그(로깅) 완벽 가이드 초보 개발자와 실무 개발자를 구분하는 가장 확실한 기준 하나를 꼽으라면 바로 '로깅(Logging)을 어떻게 다루는가?'입니다. 대학생이나 학원 시절 프로젝트에서는 에러가 나거나 변수 값을 확인하고 싶을 때 무조건 System.out.println("바로여기")를 쓰곤 했었는데요. 하지만 실제 운영(Production) 서버에서 System.out.println을 쓰면, 치명적인 성능 저하(블로킹 I/O)가 발생할 뿐만 아니라, 서버가 재시작되는 순간 콘솔에 찍힌 글자들이 흔적도 없이 증발해 버립니다.어젯밤 11시에 결제가 실패해서 고객센터로 항의가 들어왔는데, 원인을 찾으려고 보니 로그 기록이 완전히 날아가 있다면 개발자는 등골이 오싹해질 수밖에 없습니다. 이번 글에서는 장애를 역추적하는 Spring ..