첫 Rust 릴리스를 배포했는데, 20분 만에 CI가 두 번이나 빨간색으로 변했다
요약
AI 에이전트 인프라 프로젝트인 AgentOS의 첫 Rust 릴리스 과정에서 발생한 CI 실패 사례와 해결 과정을 다룹니다. Clippy 린트 오류 수정과 Linux arm64 타겟의 OpenSSL 교차 컴파일 문제를 해결하는 실무적인 경험을 공유합니다.
핵심 포인트
- Clippy 린트를 통한 코드 품질 개선 사례
- Rust 워크스페이스 기반 AI 에이전트 인프라(AgentOS) 소개
- 멀티 플랫폼 빌드 매트릭스 구성 시 주의사항
- arm64 타겟 교차 컴파일 시 OpenSSL 의존성 문제 해결
어젯밤 제 Rust 프로젝트의 첫 번째 공개 릴리스를 배포했습니다. 약 20분 만에 CI (Continuous Integration)가 두 번이나 빨간색(실패)으로 변했습니다. 무엇이 고장 났는지, 어떻게 찾아냈는지, 그리고 약간의 시간 압박 속에서 제가 했던 두 번의 호출에 대해 말씀드리겠습니다.
프로젝트
AgentOS는 AI 에이전트를 위한 런타임 레이어(runtime layer)입니다. 에이전트 로직 자체가 아니라 에이전트 '주변'의 인프라를 의미합니다: 감독된 라이프사이클 (supervised lifecycle), gRPC 메시지 버스 (message bus), 헬스 엔드포인트 (health endpoint), SSE 이벤트 스트림 (SSE event stream), 비밀 저장소 (secrets vault), 그리고 결정론적 타임 트래블 리플레이 (deterministic time-travel replay, 모든 LLM/도구 교환이 저널링되어 API 비용 없이 오프라인에서 실행을 재현할 수 있으며, 어떤 체크포인트에서든 대체 타임라인으로 포크할 수 있음)를 포함합니다.
이 프로젝트는 10개의 크레이트 (crate)로 구성된 Rust 워크스페이스이며, MIT/Apache-2.0 라이선스를 따릅니다. 한동안 비공개로 빌드해 왔습니다. 어젯밤 저장소(repo)를 공개로 전환하고 첫 번째 알파 릴리스 태그를 달았습니다. 그때부터 흥미로운 일들이 벌어졌습니다.
실패 #1: 지난달에는 없었던 clippy 린트 (lint)
저장소가 비공개였기 때문에, CI가 한동안 최신 clippy를 대상으로 실행되지 않았습니다. 공개 전환 후 커밋을 푸시하자마자 다음과 같은 내용이 나타났습니다:
error: you seem to want to iterate on a map's values
--> crates/bus/src/grpc.rs:631:37
|
...
clippy::for_kv_map 오류로, CI의 -D warnings 설정에 의해 거부되었습니다. 타당한 지적이었습니다. 코드가 HashMap을 반복(iterate)하면서 매 반복마다 키를 버리고 있었는데, 이는 정확히 .values()가 수행해야 할 역할이었습니다. 한 줄로 수정했습니다:
// 수정 전
for (_agent_id, senders) in subs.iter() {
...
푸시 후 CI는 다시 초록색(성공)이 되었습니다. 이 문제는 지루한 편이었는데, 이는 버그 중에서도 가장 좋은 종류입니다.
실패 #2: 오전 12:33, 릴리스 매트릭스 (release matrix)
더 큰 문제는 v0.1.0-alpha 태그를 달았을 때 나타났습니다. 릴리스 워크플로우는 Linux x64, Linux arm64, macOS Intel, macOS Apple Silicon, Windows 등 5개의 타겟을 병렬로 빌드하고, 각각을 체크섬 (checksum)이 포함된 바이너리 릴리스로 패키징합니다.
4개는 초록색이 되었습니다. Linux arm64가 다음과 같은 오류와 함께 중단되었습니다:
error: failed to run custom build command for `openssl-sys v0.9.116`
...
Could not find directory of OpenSSL installation
...
openssl-sys는 링크를 위해 target 아키텍처에 대한 실제 OpenSSL 설치(헤더 + 라이브러리)가 필요하며, x86_64 GitHub Actions 러너(runner)에서 arm64로 교차 컴파일(cross-compiling)할 때는 추가 설정 없이는 이를 사용할 수 없습니다. 이는 코드 버그가 아니라, 교차 컴파일(cross-compilation) 인프라의 누락된 부분입니다.
그 시점에서 저에게는 세 가지 정직한 선택지가 있었습니다:
- arm64 교차 컴파일(cross-compiling) 문제가 제대로 해결될 때까지 전체 릴리스를 차단한다.
- 시간 압박이 있고, 늦은 밤이며, 이전에 그런 방식으로 테스트해 본 적 없는 릴리스를 위해, OpenSSL을 벤더링(Vendor)하고 arm64 타겟을 위한 교차 링커(cross-linker)를 급하게 연결한다.
- 작동하는 4개의 타겟만 배포하고, 이번 릴리스에서는 arm64를 제외하며, 실제 해결책은 별도의 이슈(issue)로 추적한다.
저는 3번 옵션을 선택했습니다. 4개의 플랫폼도 이를 시도하려는 압도적인 대다수의 기여자들을 커버하는 충분한 알파 릴리스(alpha release)입니다. 알파 단계의 사용자 중 거의 아무도 사용하지 않는 Linux 아키텍처의 교차 컴파일(cross-compilation) 예외 케이스 때문에 전체를 막는 것은, 자정의 시간에 잘못된 것을 최적화하는 것처럼 느껴졌습니다. 또한 보안과 관련된 의존성(TLS)에 서둘러 수정한 해결책을 조용히 벤더링(vendoring)하는 것은 나중에 반드시 대가를 치르게 되는 바로 그런 지름길입니다.
그래서: 매트릭스(matrix)에서 해당 타겟을 제거하고, 태그를 다시 지정한 뒤, 남은 4개의 빌드가 초록색(성공)으로 변하는 것을 지켜보았습니다. 그리고 세 가지 후보 접근 방식을 정리하여 실제 해결책을 별도의 이슈로 등록했습니다 (가장 좋은 방법은 아마도 openssl-sys에서 rustls로 완전히 마이그레이션하는 것일 텐데, 이렇게 하면 arm64뿐만 아니라 모든 타겟에 대해 시스템 OpenSSL 의존성을 제거할 수 있습니다. 이러한 교차 컴파일(cross-compilation) 문제는 보통 CI 설정뿐만 아니라 의존성 선택 자체를 재검토해야 한다는 신호입니다).
이 중 어느 것을 하기 전에 실행해서 다행이라고 생각하는 단 하나의 체크
위의 사항들을 실행하기 전에, 저는 실제로 README의 자체 퀵스타트(quickstart)를 엔드 투 엔드(end-to-end)로 실행해 볼 것입니다. 즉, cargo build --workspace를 실행한 다음 예시 에이전트(example agent)를 실행하여, "README는 이것이 작동한다고 주장함"과 "이것이 실제로 작동함" 사이의 간극을 구체적으로 잡아내기 위함입니다. 실제로 그렇게 실행했고, 이제는 가상의 예시 대신 실제 터미널 출력 결과(에이전트를 생성하는 supervisor, :8080의 health server, :50051의 gRPC bus, :8081의 SSE 스트림)가 README에 포함되어 있습니다. 또한 이후에 실제로 릴리스된 Windows 바이너리를 다운로드하여 agentOS.exe --version을 실행해 보았습니다. 사소한 일이지만, 이는 "릴리스 워크플로우(release workflow)가 종료 코드 0을 반환함"과 "이 파일을 다운로드하는 낯선 사람이 작동하는 프로그램을 얻음" 사이의 차이입니다.
두 버그 모두 치명적이지는 않았습니다. 둘 다 그 순간에는 약간 스트레스를 주지만, 지나고 나면 완전히 일상적인 종류의 일들이었습니다. 릴리스 당일의 전쟁 이야기(war stories)를 포함하여, 실제 엔지니어링 작업의 대부분은 실제로 이런 모습입니다.
직접 살펴보고 싶다면, 저장소는 여기에 있습니다: github.com/WAHIB-EL-KHADIRI/AgentOS. 누군가 독립된 부분을 깊이 파고들고 싶다면, good first issue로 라벨링된 이슈들이 몇 개 있습니다. 어떤 이슈에 대해서든 질문에 답변할 준비가 되어 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기