dely Tech Blog

クラシル・TRILLを運営するdely株式会社の開発ブログです

ぼくが普段使っているOS - NixOSの話

 こんにちは。

開発部の辻です。普段はデータサイエンティスト・機械学習エンジニアをやっています。

 

本記事はdely Advent Calendar 2018の3日目の記事です。

adventar.org

 

昨日12月2日は、弊社delyの開発部プロダクトーナー兼GM奥原の記事でした。この1年でdelyは「kurashiru」の成長とともに体制も大きく変化しました。そんな中、若きプロダクトオーナー兼GMとなった彼の苦悩や意気込みなどが赤裸々に綴られています。どうぞご一読ください。

 

tech.dely.jp

 

さて、今回は特定のテーマに沿う必要はないとのことだったので、機械学習とは関係なく、ぼくが普段使っているクライアントOSの話をさせてもらおうと思います。ふつう、クライアントPCで使うOSといえば、MacOSやWindowsを使ってる方が多いかと思いますが、エンジニアの方ですと、なんらかのLinuxディストリビューションを使っている人もそれなりに多いのではないでしょうか?ぼく自身もとあるLinuxをクライアントOSとして3年ほど使っていまして、ちょっとクセの強いOSではあるのですが、使っていくうちにだんだんと安心感を感じてくる面白いOSなので、この機会にぜひご紹介させて頂きたいと思います。

 

ぼくとNixOSとの出会い

ぼくはNixOS(最新バージョンは18.09)というOSを使っています。多分ほとんどの方がご存じないと思います(笑)。ぼくはこのOSを2015年の中頃から使い始めて、最初の頃はMac上のVirtualBoxに割り当てて使っていたのですが、ある日ふと気がついたら、自宅で使っているほぼすべてのPCがNixOSになってしまいました。もちろんdelyでの開発に使っているクライアントマシンもこのNixOSです。

 

NixOS Linux

 

f:id:long10:20181126114437p:plain

  

NixOSについて

NixOSのサイトに行くと、この様な記載があります。

 

The Purely Functional Linux Distribution

NixOS is a Linux distribution with a unique approach to package and configuration management. Built on top of the Nix package manager, it is completely declarative, makes upgrading systems reliable, and has many other advantages

つまり、純粋関数型Linuxディストリビューションなのが売りと言っています。この説明にもあるように、NixOSはNixパッケージマネージャーの上に構築されていて、完全に宣言的に扱うことが可能となっています。というわけでまずはNixパッケージマネージャーについてご紹介したいと思います。

 

Nixパッケージマネージャー

Nix: The Purely Functional Package Manager

 

こちらのNixのサイトに行くと、次のように記載されています。

 

The Purely Functional Package Manager

Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. It provides atomic upgrades and rollbacks, side-by-side installation of multiple versions of a package, multi-user package management and easy setup of build environments.

やはり、純粋関数型なんですね。要するに、NixOSというのは純粋関数型パッケージマネージャー上で動くOS、だから純粋関数型OSというわけなんです。このNixパッケージマネージャーついては、いわゆる通常のパッケージマネージャーの一つですので、aptやyum、homebrewなどと同じようにパッケージを管理するのに扱えます。以下のコマンドでmacOSにインストールすることも可能です。

 インストールコマンド

curl https://nixos.org/nix/install | sh

 

Nixパッケージマネージャーは、nixpkgs(the Nix Packages Collection)に登録されているライブラリの中からパッケージをインストールします。ソースはgithubでリポジトリ管理されていて、Hydraという継続ビルド管理システムで管理されています。

 

github.com

   

Nixの仕組み

 もう少しNixの仕組みについて見ていきたいと思います。 

こちらがNix研究の元となったEelco Dolstraさんの論文です。非常にエキサイティングな内容となっています。

https://grosskurth.ca/bib/2006/dolstra-thesis.pdf 

 

全体としてはこのような外観となっています。

 

[仕組み全体の外観] 

f:id:long10:20181127131118p:plain

 

[主な仕組み]

  • パッケージレシピ関数ファイルが一意に管理される(導出コンパイル用)
  • パッケージレシピ関数はNix言語(Nix Expression Language)で記述する
  • Nix言語はパッケージ管理用DDL
  • NixはNix言語のコンパイラの役割
  • パッケージレシピ関数ファイルはNixストアにインストールされる
  • 導出コンパイル = パッケージレシピ関数のビルド + Nixストアへインストール

 

[Nix言語]

構文例はこちら

Nix Expression Language - NixOS Wiki

Nixにおけるすべての設定関数はこのNix言語で記述します。nix repl を使って構文を試すことができます。

nix-repl> rec{x = 1; y = 3; z = x + y;}.z
=> 4

 

[Nixストア]

  • インストールパッケージは必ずNixストアにインストールされる

  • ストア内に同じパッケージの複数バージョンが共存できる(※なので、HDDの結構ボリュームが消費されます。それらを整理するためにGC機能があります。)

  • インストールパッケージは、ストア内の導出ハッシュ(一意に生成されたハッシュ)によって特定されたフォルダにインストールされる

  • この一意なハッシュ名フォルダにインストールパッケージのすべてのデータが格納される(以下はtreeコマンドの例)

    $ readlink $(which tree)
    /nix/store/zzljry2r5w14rmvg3p9lz7ym326rfcpp-tree-1.7.0/bin/tree
    
    $ tree /nix/store/zzljry2r5w14rmvg3p9lz7ym326rfcpp-tree-1.7.0/
    /nix/store/zzljry2r5w14rmvg3p9lz7ym326rfcpp-tree-1.7.0/
    ├── bin
    │   └── tree
    └── share
        └── man
            └── man1
                └── tree.1.gz

 

[Nixチャンネル(nix-channel)について]

  • Nixチャンネルは特定の条件を満たすnixpkgsのバージョンを提供する仕組み
    • Hydraでビルドとテストが成功している場合に提供される
  • Nixチャンネルの種類
    • 安定チャンネル、例 nixos-18.09
    • 不安定(開発): nixos-unstable
    • サーバ向け、例 nixos-18.09-small, nixos-unstable-small
  • Nixストア内にはNixチャンネルの最新nixpkgsが入っていてNixに利用される
  • Hydraでインストールパッケージがビルドされ、自動的にバイナリパッケージが生成される(これが特定のチャンネルとして提供される) 

 

NixOSの仕組み

NixOSは、このようにNixパッケージマネージャーを中心で構成されているOSなのでした。まとめるとNixOS自体はこのような外観をしています。

 

NixOS全体の外観 

f:id:long10:20181127140859p:plain

 

 

NixOSを使うと以下のような恩恵を受けられます。

  • モジュールシステム(宣言型設定)
  • Dependency Hellからの脱却
  • ロールバック
  • 軽量コンテナー (systemd-nspawn利用)
  • Dev/Opsツール (NixOps)

 

モジュールシステム(宣言型設定)

 

なんと言ってもNixOSといえばこれという機能です。

様々な設定やパッケージ管理、システムの自動化などを宣言的に管理することができます。モジュールシステムはnixpkgs内に含まれていてNix言語を使って記述します。

 

NixOSのメインとなる情報はこのファイルに宣言的に記載します。

 /etc/nixos/configuration.nix

 

宣言的に設定した例をいくつか紹介します。 

プロビジョニングの例

environment.systemPackages = with pkgs; [
  firefox
  termite
  tmux
];

 systemdのサービス

systemd.services.ircSession = {
  wantedBy = [ "multi-user.target" ];
  after = [ "network.target" ];
  serviceConfig = {
    Type = "forking";
    User = "username";
    ExecStart = ''${pkgs.tmux}/bin/tmux new-session -d -s irc -n irc ${pkgs.irssi}/bin/irssi'';
    ExecStop  = ''${pkgs.tmux}/bin/tmux kill-session -t irc'';
  };
};

 cronのサービス

systemd.services.cron = {
 enable = true;
 systemCronJobs = [
 "30 00 * * * sh hogehoge.sh"
 ];
};

 

Dependency Hellからの脱却

 

インストールパッケージは、ストア内の導出ハッシュによって特定されたフォルダにインストールされるので、たとえばバージョンの異なる2つのパッケージが上書きされることもなく(別のハッシュ値が生成されるため)、またパッケージが依存する別のパッケージについてもこの導出ハッシュを用いてビルドされるため、相互的に依存し合うパッケージは存在しません。ですので、インストール時に毎回、環境依存に怯えながらインストールすることはなくなります。(この点に関してはDockerを使えば問題は解決すると思いますが、NixOS上でもDockerはもちろん使えますので、ぼくの場合は用途によって適宜使い分けています。)

 

ロールバック

 

なんらかのsystem設定を間違えてしまったために、OSが起動しなくなってオワタという経験も、NixOSを使えばさっとロールバックできるから安心です。 

  • コマンドでロールバック可能

  • ブート画面でロールバック可能

 

 GRUB画面で前のリビジョンを選択して起動する

f:id:long10:20181127132620p:plain

 

NixOSの再構築

  • nixos-rebuild コマンドで変更した設定を適応する

    $ nixos-rebuild switch
  • 設定をビルドのみする場合(コンパイルチェック)

    $ nixos-rebuild build
  • 宣言的にOSを管理できるので、configuration.nixを別のPCにコピーし、この手順で適応すれば同じ環境を再現できる

 

NixOps Dev/Opsツール

 

NixOSのDev/OpsツールとしてNixOpsがあります。NixOSはDev/Opsを大変重要視した設計思想となっていて、NixOpsを使うことで、デプロイ先のハードウェアや仮想マシンに対してNixOSのセットを展開することができます。また、NixOSのシステム構成管理はクライアントPCとシームレスに管理でき、宣言的なアプローチをネットワークにも拡張し、さらにそのプロビジョニングを追加することができます。ぼくが所有している複数のNixOSマシンについてもNixOpsを用いて設定構成をネットワーク拡張して使用しています。

 

NixOSの不便なところ

 NixOSはとても便利かつ安心して利用できるOSなのですが、すべての人にとってそう言えるかといえばなかなかそれは難しい面もあります。

たとえばこんな点です。

  • クセが強いので慣れるまでに時間がかかる
  • 利用できるパッケージが他のパッケージより少ないので、ないパッケージは自分でビルドする必要がある(ものによっては結構難しい。。)
  • ちょっとしたことを試すのが面倒(そんなときこそDockerを使いましょう)

Dockerのサービス起動もたったのこれだけです。

{
  virtualisation = {
    docker.enable = true;
  };
}

 

終わりに

いかがでしたでしょうか?

NixOSの特性についてざっくりとご紹介させて頂きました。NixOSを使うことで、いわゆる”Dependency Hell”から開放され、依存関係の完結が保証されることで、堅牢な管理や安全なロールバックが可能となります。NixOSには今回ご紹介できなかった機能がまだまだたくさんありますので、もしご興味を持っていただけたらぜひお試し頂けると嬉しいです。

 

不定期開催ですがMeetupやってます!

www.meetup.com

 

余談ですが、今年のNix Conference(Nixcon 2018)で、Nixを使ったデータパイプラインの設定についてのセションがあって個人的にとても興味深かったです。機械学習やパイプライン基盤にもNixOSを使うと面白そうですね。

 

Georges Dubus - Nix for data pipeline configuration.pdf - Google ドライブ

 


Georges Dubus - Nix for data pipeline configuration

 

さて、dely Advent Calendarの明日のタイトルは、『超手軽に構築する!サーバレスなWEBパフォーマンス定点観測基盤』です。お楽しみに!