380 Views
October 10, 24
スライド概要
Nix で Rust の開発環境から CI,Deploy まで管理する
TUI の Feed Viewer を自宅の Raspbery Pi で 公開するまで Nix で Rust の開発環境から CI,Deploy まで管理する 山口 裕太 · 2024‑03‑05
自己紹介 [speaker] name = "Yamaguchi Yuta" github = "https://github.com/ymgyt" blog = "https://blog.ymgyt.io/"
会社紹介 [company] name tech_blog = "FRAIM Inc." = "https://zenn.dev/p/fraim"
作成したツールのライフサイクルについて 話すこと • TUI の Feed Viewer を作った • Nix で開発環境,CI,Deploy を管理した • Release では cargo‑release と cargo‑dist を利 用した • Trace,Metrics,Logs は OpenTelemetry を利用し た
Rust で TUI Feed の Entry 一覧
Rust で TUI Feed の一覧
Rust の TUI library 1. crossterm(cross platform terminal library) 2. ratatui(tui widgets library)
Rust の TUI library Netflix が公開した eBPF の tui tool でも ratatui が使われている
let (header, widths, rows) = self.entry_rows(cx); ratatui let entries = Table::new(rows, widths) .header(header.style(cx.theme.entries.header)) .column_spacing(2) .style(cx.theme.entries.background) .highlight_symbol(ui::TABLE_HIGHLIGHT_SYMBOL) .highlight_style(cx.theme.entries.selected_entry) .highlight_spacing(HighlightSpacing::WhenSelected); Table や List 等の基本的な widget が用意されている
crossterm
async fn event_loop<S>(&mut self, input: &mut S)
where
S: Stream<Item = io::Result<CrosstermEvent>> +
Unpin,
{
loop {
tokio::select! {
biased;
Some(event) = input.next() => { }
_ = self.background_jobs => { }
};
}
複数の入力も async で書ける
crossterm
fn handle_terminal_event(&mut self, event:
std::io::Result<CrosstermEvent>) {
match event.unwrap() {
CrosstermEvent::Resize(columns, rows) => { }
CrosstermEvent::Key(key) => match key.code {
KeyCode::Tab => { },
KeyCode::Char('j') => { },
}
}
}
Key 入力の処理も簡単
Nix による開発 環境の管理 この Rust の project を Nix で管理しました
そもそも Nix とは Nix による開発 環境の管理 > A build tool, package manager, and programming language https://zero‑to‑nix.com/concepts/nix
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる
{
Nix による開発
環境の管理
inputs.nixpkgs.url = "github:NixOS/nixpkgs/
release-23.11";
outputs = { self, nixpkgs, ... }:
let dev_packages = with pkgs; [
graphql-client
git-cliff
cargo-release
cargo-dist
oranda
];
in { devShells.default = craneLib.devShell {
packages = dev_packages;
};
});
}
project root の flake.nix で開発時の依存を宣言
nix develop nix develop を実行すると宣言した package が PATH に入った状態で開発環境(shell)が立ち上が る
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる • CI を Nix で管理できる
CI でも nix develop name: CI jobs: tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: nix develop .#ci --acceptflake-config --command just check • install action が不要 • 開発環境と同一 version
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる • CI を Nix で管理できる • Cache を Nix で管理できる
Nix で管理する と何がうれし いのか /nix/store/3sn5pij1hjvdlnq468c0m8vz8nibhrdccargo-release-0.25.0/bin/cargo-release の 3sn5pij1hjvdlnq468c0m8vz8nibhrdc が入力に対 応する hash となっており、cache があれば build せずに binary を取得できる
Nix で管理する と何がうれし いのか cache から取得
Nix で管理する と何がうれし いのか name: CI jobs: tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v25 with: github_access_token: ${{ secrets.GITHUB_TOKEN }} - uses: cachix/cachix-action@v14 with: name: syndicationd authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - run: nix develop .#ci --accept-flake-config -command just check cache を設定した最終的な CI の workflow local と CI で同じ cache の仕組みを利用できる
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる • CI を Nix で管理できる • Cache を Nix で管理できる • Install を Nix で管理できる
Nix で管理する と何がうれし いのか nix run で一時的に実行したり nix profile で install もできる Mac と Linux で同じ package 管理ができる
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる • CI を Nix で管理できる • Cache を Nix で管理できる • Install を Nix で管理できる • Deploy を Nix で管理できる
Nix で systemd
service を宣言
{ config, pkgs, syndicationd, ... }:
let
syndPkg = syndicationd.packages."${pkgs.system}".syndapi;
in {
config = {
systemd.services.synd-api = {
description = "Syndicationd api";
wantedBy = [ "multi-user.target" ];
environment = {
SYND_LOG = "INFO";
};
serviceConfig = {
ExecStart = "${syndPkg}/bin/synd-api"
};
};
};
}
https://github.com/ymgyt/mynix/blob/main/homeserver/
modules/syndicationd/default.nix
Nix で Deploy deploy‑rs で NixOS が入った RaspberryPi に deploy
Nix で管理する と何がうれし いのか • 開発環境を Nix で管理できる • CI を Nix で管理できる • Cache を Nix で管理できる • Install を Nix で管理できる • Deploy を Nix で管理できる
cargo でも公開 したい とはいえ、cargo install もしたい
cargo publish するには以下が必要 cargo でも公開 したい • Cargo.toml の package.version の bump • Workspace 内に依存 package がある場合は合 わせて bump • CHANGELOG の生成 • git の tagging これを workspace の member crate ごとに実施 する必要がある
cargo でも公開 したい cargo‑release が全て面倒をみてくれる
cargo release --package foo patch を実行する cargo でも公開 したい と • foo package の Cargo.toml package.version を bump(v0.1.2 ‑> v0.1.3) • foo に依存している workspace 内の package の dependencies.foo.version を bump • 設定に定義した replace 処理を実施 (CHANGELOG の[unreleased] ‑> [v0.1.3]) • git の commit, tagging, push • cargo publish
homebrew で も公開したい brew install もしたい
専用の repository(homebrew-syndicationd)に以下 のような記述が必要 homebrew で も公開したい class Synd < Formula desc "terminal feed viewer" version "0.1.6" on_macos do on_arm do url "https://github.com/ymgyt/syndicationd/releases/download/syndterm-v0.1.6/synd-term-aarch64-apple-darwin.tar.gz" sha256 "c02751ba979720a2a24be09e82d6647a6283f28290bbe9c2fb79c03cb6dbb979" end on_intel do url "https://github.com/ymgyt/syndicationd/releases/download/syndterm-v0.1.6/synd-term-x86_64-apple-darwin.tar.gz" sha256 "3be81f95c68bde17ead0972df258c1094b28fd3d2a96c1a05261dba2326f31d8" end end
homebrew で も公開したい cargo‑dist が全て面倒をみてくれる
cargo dist init を実行して質問に答えると cargo‑dist が やってくれる • Cargo.toml の[workspace.metadata.dist]に設 定が追加 • .github/workflows/release.yml を生成
cargo dist init を実行して質問に答えると cargo‑dist が やってくれる • Cargo.toml の[workspace.metadata.dist]に設 定が追加 • .github/workflows/release.yml を生成 この状態で cargo‑release で git tag を push する と
cargo‑dist が やってくれる Github release と各種 installer が作成される
cargo‑dist が やってくれる cargo‑dist が以下をやってくれる(設定次第) • 各種 platform(aarch64,x86 の darwin,windows, linux gnu,musl)向けの binary 生成 • shell,powershell の install script 作成 • homebrew 用 repository の更新(push 権限を渡 す必要あり)
cargo‑dist が やってくれる cargo dist plan を実行すると CI で実行される 内容を確認できる workflow yaml にベタ書きされているのではな く、cargo dist plan の出力を参照するように なっている
cargo‑dist が やってくれる cargo‑release と一緒に使うことが想定されてお り cargo publish と git の tag push までが cargo‑ release それ以降の配布処理が cargo‑dist という役割分 担がよかったので使ってみた
監視もしたい Deploy と Release ができたので次に監視がした い
監視もしたい Deploy と Release ができたので次に監視がした い OpenTelemetry を使う
Rust で OpenTelemetry Rust で tracing を使っている場合 tracing-opentelemetry と opentelemetry_sdk を 使うと Logs, Traces, Metrics を取得できる
Rust で OpenTelemetry 公開している Grafana dashboard
Rust で OpenTelemetry Entry 取得時の Trace
まとめ Nix,cargo‑{release,dist},OpenTelemetry で 楽しいツール開発
各種 link • cargo‑release • cargo‑dist • deploy‑rs • syndicationd • raspi nix configuration