Rust 실전 강좌 #8 배포: crates.io 발행과 GitHub Releases 자동화로 완결
마지막 편입니다. 도구는 완성됐고(1〜5편), 테스트가 지키고 있고(6편), 어느 플랫폼용 바이너리든 만들 수 있습니다(7편). 남은 것은 세상에 내놓는 일이고, 경로는 두 갈래입니다. Rust 개발자를 위한 crates.io, 그리고 Rust가 없는 사용자를 위한 GitHub Releases입니다.
crates.io: cargo install의 세계 #
crates.io는 기초 9편에서 의존성을 받아 온 그 저장소이고, 발행도 같은 곳으로 합니다. 먼저 Cargo.toml의 메타데이터를 채웁니다.
[package]
name = "loglens"
version = "0.1.0"
edition = "2024"
description = "액세스 로그 통계·상위 경로·에러 추출 CLI"
license = "MIT OR Apache-2.0"
repository = "https://github.com/example/loglens"
keywords = ["log", "cli", "nginx"]
categories = ["command-line-utilities"]description과 license는 발행 필수 항목입니다. 라이선스의 MIT OR Apache-2.0 이중 표기는 Rust 생태계의 관례적 기본값이라 특별한 사정이 없으면 따르는 것이 무난합니다. 발행 절차는 리허설부터입니다.
cargo publish --dry-run # 패키징·검증만 수행
cargo publish # 실제 발행 (crates.io 로그인 필요)발행 전에 알아야 할 규칙이 하나 있습니다. crates.io의 버전은 영구적입니다. 삭제도 덮어쓰기도 없고, 문제가 있는 버전은 cargo yank로 “신규 사용 차단” 표시만 할 수 있습니다(이미 lock 파일에 고정한 사용자는 계속 받을 수 있습니다. 의존성 그래프를 깨뜨리지 않기 위한 설계입니다). 실수한 버전은 고친 다음 버전을 올리는 것이 정답이고, 그래서 dry-run이 리허설로서 의미를 갖습니다. 발행이 끝나면 사용자 경험은 한 줄입니다.
cargo install loglens사용자의 기계에서 release 빌드가 수행되어 ~/.cargo/bin에 들어갑니다. 파이썬 패키징 편에서 본 PyPI 발행과 같은 구도인데, 가상 환경이나 런타임 버전 고민이 없는 것이 컴파일 언어의 이점입니다.
GitHub Releases: Rust 없는 사용자에게 #
cargo install은 사용자에게 Rust 도구 체인을 요구합니다. 서버 관리자에게 “먼저 rustup을 설치하시고"라고 말할 수는 없으므로, 완성 바이너리를 내려받는 경로가 필요합니다. 그 관례적 자리가 GitHub Releases이고, 7편에서 만든 타깃 목록(리눅스 musl, 맥 2종, Windows)이 여기 올라갈 파일들입니다.
손으로 네 번 빌드해 올릴 수도 있지만, 릴리스마다 반복할 일은 자동화 대상입니다. GitHub Actions 강좌 4편에서 다룬 매트릭스가 정확히 이 문제의 도구입니다.
# .github/workflows/release.yml (핵심부)
on:
push:
tags: ["v*"]
jobs:
build:
strategy:
matrix:
include:
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl }
- { os: macos-latest, target: aarch64-apple-darwin }
- { os: macos-latest, target: x86_64-apple-darwin }
- { os: windows-latest, target: x86_64-pc-windows-msvc }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: rustup target add ${{ matrix.target }}
- run: cargo test
- run: cargo build --release --target ${{ matrix.target }}
# 이후: 산출물 압축 → 릴리스에 업로드읽는 법은 이렇습니다. v0.1.0 같은 태그를 푸시하면 워크플로가 깨어나고, 매트릭스의 4개 조합이 각자의 OS 러너에서 병렬로 빌드됩니다. 7편에서 예고했듯 각 OS가 자기 몫을 빌드하므로 크로스 컴파일의 링커 문제는 리눅스 musl 타깃 정도로 줄어듭니다. cargo test가 빌드 앞에 있는 것도 우연이 아닙니다. 6편의 테스트가 3개 OS에서 전부 통과해야 릴리스가 만들어지는, 태그 하나로 검증부터 배포까지 이어지는 파이프라인입니다.
시리즈를 마치며 #
8편의 여정을 도구의 이력서로 요약하면 이렇습니다. 인터페이스가 타입으로 선언되어 있고(clap), 실패가 설계되어 있고(anyhow·thiserror), 메모리 사용이 예측 가능하고(BufReader 스트리밍), 코어를 전부 쓰며(rayon), 동작이 테스트로 문서화되어 있고(assert_cmd), 어디서나 도는 단일 바이너리로(musl), 태그 하나에 자동 배포됩니다(Actions). 각 편의 결정이 쌓여 “동작하는 코드"가 “남에게 권할 수 있는 도구"가 됐습니다.
기초 강좌가 문법의 등뼈였다면 이번 강좌는 근육이었습니다. 다음 걸음으로는 자기 업무의 반복 작업 하나를 같은 골격(clap → 에러 설계 → 코어 로직 → 테스트 → 배포)으로 도구화해 보시기를 권합니다. 두 번째 도구는 놀랄 만큼 빨리 만들어질 것입니다.
정리 #
- crates.io 발행은 메타데이터(description, license 필수) →
--dry-run리허설 →cargo publish순서입니다. 발행된 버전은 영구적이고, 문제 버전은 yank로 신규 사용만 차단합니다. cargo install loglens가 Rust 개발자용 설치 경험입니다. 런타임 걱정이 없는 것이 컴파일 언어의 이점입니다.- Rust 없는 사용자에게는 GitHub Releases에 완성 바이너리를 올립니다. 7편의 타깃 목록이 그대로 배포 파일 목록입니다.
- 태그 푸시 → 매트릭스 빌드 → 릴리스 업로드가 자동화의 골격입니다. 각 OS 러너가 각자 빌드하므로 크로스 컴파일 부담도 줄어듭니다.
- 테스트가 빌드 앞에 서는 파이프라인이 완성입니다. 태그 하나로 검증부터 배포까지, 실전 강좌는 여기까지입니다.