[dev] 주간 기술 아티클 다이제스트
이번 다이제스트 기준
Jekyll 블로그 자동 발행 파이프라인을 만들고 나서 가장 먼저 막힌 부분은 의외로 콘텐츠 생성이 아니라 로컬 빌드 환경이었습니다.
겉으로 보기에는 단순히 bundle exec jekyll build가 실패하는 문제였지만, 실제로는 여러 문제가 한 번에 겹쳐 있었습니다.
결과적으로 자동화 스크립트가 아무리 잘 만들어져 있어도, 로컬에서 재현 가능한 빌드 환경이 없으면 운영 신뢰성이 떨어질 수밖에 없었습니다.
가장 먼저 확인된 오류는 Ruby 실행 파일과 연결된 런타임 경로가 잘못된 위치를 바라보는 문제였습니다.
which ruby
rbenv which ruby
otool -L "$(rbenv which ruby)"
확인 결과에서는 현재 사용자 홈 디렉터리가 아니라, 다른 사용자의 rbenv 경로에 있는 libruby를 참조하려고 했습니다.
이 상태에서는 Jekyll 문제를 보기 전에 Ruby 런타임 자체가 이미 깨져 있는 상태였습니다.
우선 이 저장소에서 사용 중이던 Ruby 3.2.2를 다시 설치해서 잘못 연결된 바이너리 문제를 먼저 정리했습니다. 여기서는 저장소의 기존 실행 흐름과 맞추는 것이 우선이었기 때문에, 다른 버전으로 올리기보다 현재 기준 버전을 복구하는 쪽을 택했습니다.
rbenv uninstall -f 3.2.2
rbenv install 3.2.2
rbenv rehash
이후 ruby -v는 정상적으로 동작했지만, 문제는 여기서 끝나지 않았습니다.
다음 단계에서 bundle install을 실행하자 eventmachine, ffi 같은 native gem에서 빌드가 실패했습니다.
대표적으로 아래와 같은 문제가 있었습니다.
binder.cpp 컴파일 실패iostream 헤더를 찾지 못하는 문제ffi 빌드 중 assembler/CFI 관련 오류처음에는 단순히 gem 버전 문제라고 생각했지만, 로그를 자세히 보니 C++ 빌드 환경과 SDK 경로가 더 근본적인 원인이었습니다.
macOS에서는 Ruby native gem 빌드가 Command Line Tools 상태에 직접 영향을 받습니다.
그래서 아래를 확인했습니다.
xcode-select -p
softwareupdate --list
확인 결과 최신 Command Line Tools 업데이트가 남아 있었고, 실제로 이를 설치한 뒤 SDK 디렉터리 구성이 달라졌습니다. 다만 아래 패키지명은 제가 작업한 당시 이 Mac 환경에서 보였던 값이므로, 다른 시점이나 다른 장비에서는 이름이 달라질 수 있습니다.
softwareupdate --install "Command Line Tools for Xcode 26.4-26.4"
업데이트 후에는 SDK 안쪽에 C++ 헤더 경로가 정상적으로 보이기 시작했습니다.
스크린샷 포인트 1:
softwareupdate --list결과
문제는 Command Line Tools를 설치해도 Ruby가 native gem을 빌드할 때 적절한 C++ 플래그를 자동으로 잡지 못했다는 점입니다.
그래서 scripts/ruby_cxx_fix.rb를 추가해 Ruby의 컴파일 설정에 아래 값을 주입했습니다. 이 방법은 일반적인 정답이라기보다, 이 저장소와 이 로컬 환경에서 재현 가능한 빌드를 만들기 위한 저장소 전용 우회책에 가깝습니다.
isysroot 경로usr/include/c++/v1 경로-stdlib=libc++또한 fallback 경로로 사용한 /opt/homebrew/... 값 역시 Apple Silicon Homebrew 기준이어서, 다른 Mac에서는 경로를 다르게 잡아야 할 수 있습니다.
핵심 아이디어는 “매번 쉘 환경을 수동으로 고치는 대신, Ruby가 빌드 시점에 필요한 플래그를 일관되게 적용하게 만들자”는 것이었습니다.
구조는 대략 아래와 같습니다.
[RbConfig::CONFIG, RbConfig::MAKEFILE_CONFIG].each do |config|
config['CXX'] = cxx
config['CPPFLAGS'] = [config['CPPFLAGS'], extra_cppflags].compact.join(' ').strip
config['CXXFLAGS'] = [config['CXXFLAGS'], '-stdlib=libc++'].compact.join(' ').strip
end
이후 RUBYOPT로 이 파일을 로드해서 bundle install과 jekyll build를 실행하도록 구성했습니다.
환경이 한 번 맞더라도, 실행 방식이 제각각이면 다시 깨질 가능성이 큽니다.
그래서 scripts/jekyll-build.sh를 추가해서 로컬 빌드 루틴을 한 줄로 고정했습니다.
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
RUBYOPT_FIX="-r${ROOT_DIR}/scripts/ruby_cxx_fix.rb"
cd "$ROOT_DIR"
RUBYOPT="$RUBYOPT_FIX" bundle install
RUBYOPT="$RUBYOPT_FIX" bundle exec jekyll build
이제는 아래 명령 하나로 로컬 재현이 가능합니다.
npm run jekyll:build
최종적으로는 아래 검증이 모두 성공했습니다.
npm run jekyll:build
python3 scripts/validate_dev_digest.py _posts/dev/digest/2026-03-16-dev-digest.markdown --min-items 1
즉, 단순히 에러 메시지를 없앤 것이 아니라 아래 두 가지를 모두 만족하게 되었습니다.
스크린샷 포인트 2:
npm run jekyll:build성공 로그
이번 문제를 해결하면서 가장 크게 느낀 점은, 블로그 자동화에서 중요한 것은 Python 스크립트나 GitHub Actions 자체보다도 기반 런타임을 재현 가능하게 유지하는 것이라는 사실이었습니다.
특히 Jekyll처럼 Ruby 생태계와 로컬 툴체인 영향을 받는 프로젝트는 아래가 중요합니다.
즉, 자동화는 발행 단계만 자동이면 끝나는 게 아니라, 실패했을 때도 같은 방식으로 복구할 수 있어야 진짜 자동화라고 볼 수 있습니다.
이번 복구 작업 덕분에 이 블로그는 다시 “글을 올릴 수 있는 상태”가 되었고, 그 위에서 자동 digest와 품질 게이트도 안정적으로 운영할 수 있게 되었습니다.
나중에 시간이 더 생기면 다음도 정리해보고 싶습니다.
faraday-retry 경고 정리비슷한 문제를 겪고 있다면, 에러 메시지만 보고 gem 버전을 계속 바꾸기보다 Ruby 경로 -> SDK 상태 -> C++ 헤더 경로 -> 빌드 루틴 고정 순서로 보는 것이 훨씬 빠를 수 있습니다.
이번 다이제스트 기준
Jekyll 블로그에 build, 링크 검사, Ruby 의존성 점검을 붙여 발행 전 품질 게이트를 만든 과정입니다.
rbenv 경로 꼬임, native gem 빌드 실패, macOS CLT 문제를 정리하고 Jekyll 로컬 빌드를 복구한 기록입니다.
Jekyll 블로그에 RSS 수집, Markdown 생성, 검증, 빌드, 자동 push를 연결한 발행 파이프라인 구축기입니다.
이번 다이제스트 기준
이번 다이제스트 기준
개요 linux를 사용하다 보면 version 비교하는 기능이 필요합니다. 특히 기존 설치된 패키지의 version을 확인하여 업데이트할 경우가 있겠죠. 아래와 같이 간단한 shell script로 구현할 수 있습니다.
jdk 21 출시!!
ci/cd 오픈소스 도구로 가장 많이 사랑 받는 jenkins에 대해 포스팅 해보겠습니다. 먼저 설치부터 해야겠지요? 항상 패키지 매니저로 설치했었는데 이번에는 docker로 설치해보도록 하겠습니다.
개요 github rest API 문서를 보면 재미있는 API들이 있습니다. 오늘은 그 중 최신 release 가져오는 API를 만져보도록 하겠습니다.
개요 intellij에서 shell script 코드를 작성할 때 이런 warning 메시지를 보여주더군요.
springboot 탄생 배경 springboot란 spring framework를 좀 더 쉽게 개발/배포할려는 목적으로 만들어 졌습니다. 2012년 Mike Youngstrom은 spring 프레임워크에서 컨테이너 없는 웹 애플리케이션 아키텍처에 대한 지원을 요청하는 spring...
개요 지난번 spring-initializer를 통해 프로젝트를 생성하여 파일로 다운로드 받았습니다.
개요 springboot3로 메이저 업그레이드 되면서 JPA + querydsl 셋팅 환경에 변화가 생겼습니다. 기존 의존성으로는 작동하지 않고 jakarta classification을 추가해야 작동하는 이슈가 발생합니다. springboot3부터 javax -> jakar...
개요 2022년 하반기에 springboot3가 공식 release 되었습니다. springboot2가 2018년 상반기에 release되고 나서 새롭게 판올림 버전으로 가장 큰 변화로는 아래와 같습니다. spring framework 6 적용 최소 사양 JDK 17 ...
개요 항상 intellij ultimate 버전만 사용하고 있었는데 무슨 바람이 난건지.. intellij ce 버전에 도전하였습니다. springboot 프로젝트 생성이며.. 그 밖에 기본적으로 될꺼라 싶은것 중에 안되는 녀석들도 꽤 있더군요. 이번 시간엔 간단하게 spingbo...
개요 JPA를 spring data jpa + querydsl과의 조합으로 접하는 경우가 많습니다. spring data jpa에서 제공해주는 specification으로도 충분히 해낼수 있지만 querydsl에 비할바는 아닙니다. entity에 wrapper Q클래스를 생성하여 ...
개요 오랫동안 방치했던 블로그를 다시 열면서 jekyll를 다시 설치해봤습니다. 설치 jekyll 프로젝트로 이동하여 아래 명령어를 입력합니다. gem install jekyll bundler Fetching pathutil-0.16.2.gem Fetching terminal-t...
개발자에게 있어 탁월한 검색은 능력은 필수라고 생각됩니다.
bash를 사용하여 yaml 파일을 파싱 및 환경 변수로 손쉽게 등록할 수 있습니다.
https://app.diagrams.net/
구글 검색을 해보면 Spring Boot Gradle + 하나의 vueJS Project Build만 나와있는 경우가 많습니다.
외부 통신에 대한 Error 처리는 앱을 더욱 더 견고하게 만들 수 있습니다. Error 처리를 위해 엔드포인트에 대한 Http Status Code를 억지로 생성하는것은 매우 귀찮은 일이라고 할까요? 보다 간편하게 Mock 서버를 두는게 더 효율적이라고 볼 수 있습니다.
입력 받은 아이디를 체크하여 규칙에 맞게 추천하는 프로그램 개발 7단계의 규칙을 적용해야 하는데 그 내용은 아래와 같다.