IT General
น้องๆ เคยเจอปัญหาลงโปรแกรมแล้วตีกันมั้ย? หรือโปรแกรมที่เคยใช้ได้ ดันรันไม่ได้หลังจากอัพเดท? สมัยผมทำร้านเน็ตนี่เจอบ่อยมาก! ลูกค้าลงเกม ลงโปรแกรมเอง พังกันระนาว Nix Package Manager เนี่ยแหละคือพระเอกที่จะมาช่วยแก้ปัญหาเหล่านี้
Nix มันคือ package manager แบบ functional ที่ฉลาดมากๆ มันจัดการ dependencies (โปรแกรมที่โปรแกรมเราต้องพึ่งพา) ได้อย่างเทพ ทำให้เรามั่นใจได้ว่าโปรแกรมที่เราลง จะทำงานได้อย่างที่เราต้องการ ไม่ว่าจะผ่านไปกี่ปีก็ตาม แถมยังช่วยให้เราสร้าง environment ที่ reproduceable ได้ง่ายๆ อีกด้วย
สำคัญยังไงน่ะเหรอ? ลองนึกภาพว่าเรามีโปรเจค 10 โปรเจค แต่ละโปรเจคต้องการ Python เวอร์ชั่นไม่เหมือนกัน ถ้าใช้ package manager ทั่วไป เราต้องสลับเวอร์ชั่น Python ไปมา วุ่นวายมาก! แต่ Nix ช่วยให้เราสร้าง environment แยกกันสำหรับแต่ละโปรเจคได้เลย สบายแฮ
Nix ใช้ configuration file ที่เรียกว่า Nix expression เพื่ออธิบายว่าเราต้องการอะไร ไม่ใช่ทำอะไร (declarative vs. imperative) เหมือนเราสั่งอาหารตามเมนู เราบอกว่าเราจะกินอะไร ไม่ใช่บอกว่าต้องทำอาหารยังไงบ้าง
{ pkgs ? import <nixpkgs> { } }:
pkgs.stdenv.mkDerivation {
name = "hello-world";
version = "1.0";
src = ./.;
buildPhase = "echo 'Building...'";
installPhase = "mkdir -p $out/bin; echo '#!/bin/sh\necho Hello, world!' > $out/bin/hello; chmod +x $out/bin/hello";
}
โค้ดด้านบนคือตัวอย่าง Nix expression ง่ายๆ ที่สร้าง package ชื่อ hello-world มันบอกว่าเราต้องการสร้าง package ที่มีไฟล์ executable ชื่อ hello ที่แสดงข้อความ "Hello, world!"
Nix สร้าง environment ที่ reproduceable ได้ หมายความว่าถ้าเราสร้าง package ด้วย Nix expression เดียวกัน เราจะได้ package ที่เหมือนกันทุกประการ ไม่ว่าเราจะสร้างมันบนเครื่องไหน เมื่อไหร่ก็ตาม สมัยผมดูแลเครื่องในร้านเน็ต ถ้าลงโปรแกรมด้วย Nix นี่สบายใจเลย ลงเครื่องไหนก็เหมือนกันเป๊ะ
Reproducibility นี่สำคัญมากสำหรับการทำงานเป็นทีม เพราะทุกคนจะได้ใช้ environment ที่เหมือนกัน ลดปัญหา "It works on my machine!" ได้เยอะ SiamCafe Blog มีบทความเกี่ยวกับการทำงานเป็นทีม ลองไปอ่านดูนะ
Nix store (ที่เก็บ package) เป็น immutable นั่นหมายความว่าเมื่อ package ถูกสร้างแล้ว มันจะไม่สามารถเปลี่ยนแปลงได้อีก ถ้าเราต้องการเปลี่ยนแปลง package เราต้องสร้าง package ใหม่เท่านั้น ข้อดีคือมันช่วยป้องกันปัญหา package corruption และทำให้เรามั่นใจได้ว่า package ที่เราใช้ปลอดภัย
เริ่มต้นใช้งาน Nix ไม่ยากอย่างที่คิด แค่ลง Nix package manager แล้วเริ่มเขียน Nix expression ง่ายๆ ก็พอ
การติดตั้ง Nix ขึ้นอยู่กับระบบปฏิบัติการที่เราใช้ วิธีที่ง่ายที่สุดคือเข้าไปที่เว็บไซต์ NixOS download page แล้วทำตามคำแนะนำ
สมัยผมเริ่มใช้ Nix แรกๆ ก็งงๆ เหมือนกัน แต่พอใช้ไปสักพักจะเริ่มเข้าใจหลักการทำงานของมันเอง
ลองสร้างไฟล์ชื่อ `default.nix` แล้วใส่โค้ดด้านล่างลงไป
{ pkgs ? import <nixpkgs> { } }:
pkgs.stdenv.mkDerivation {
name = "my-app";
version = "1.0";
src = ./.;
buildPhase = "echo 'Building...'";
installPhase = "mkdir -p $out/bin; echo '#!/bin/sh\necho Hello, from my app!' > $out/bin/my-app; chmod +x $out/bin/my-app";
}
โค้ดนี้จะสร้าง package ชื่อ my-app ที่มีไฟล์ executable ชื่อ my-app ที่แสดงข้อความ "Hello, from my app!"
เปิด terminal แล้วพิมพ์คำสั่ง `nix-build`
nix-build
Nix จะ build package ของเรา และสร้าง symbolic link ไปยัง directory ที่เก็บ package ที่ build เสร็จแล้ว
เข้าไปใน directory ที่เก็บ package ที่ build เสร็จแล้ว แล้วรันไฟล์ executable
./result/bin/my-app
เราจะเห็นข้อความ "Hello, from my app!" แสดงขึ้นมา
Nix shell เป็น feature ที่ทำให้เราสร้าง environment ที่มี dependencies ที่เราต้องการได้ง่ายๆ สมมติว่าเราต้องการ environment ที่มี Python 3.9 และ requests package เราสามารถสร้างไฟล์ชื่อ `shell.nix` แล้วใส่โค้ดด้านล่างลงไป
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
buildInputs = [
pkgs.python39
pkgs.python39Packages.requests
];
}
จากนั้นรันคำสั่ง `nix-shell`
nix-shell
Nix จะสร้าง environment ที่มี Python 3.9 และ requests package ให้เรา เราสามารถ activate environment นี้ได้โดยใช้คำสั่ง `source ./result/activate`
Nix shell นี่แหละที่ช่วยให้ผมจัดการ environment ของโปรเจคต่างๆ ในร้านเน็ตได้ง่ายขึ้นเยอะ SiamCafe Blog มีบทความเกี่ยวกับการจัดการ environment ด้วย Nix Shell ลองไปอ่านดูนะ
Nix ไม่ใช่ package manager ตัวเดียวในโลก ยังมีทางเลือกอื่นๆ อีกมากมาย เช่น APT, YUM, Homebrew แต่ละตัวก็มีข้อดีข้อเสียแตกต่างกันไป
| Package Manager | ข้อดี | ข้อเสีย |
|---|---|---|
| Nix | Reproducibility, Immutability, Declarative configuration | Learning curve สูง, syntax เข้าใจยาก |
| APT (Debian/Ubuntu) | ใช้งานง่าย, package เยอะ | Dependency management ไม่ดีเท่า Nix, reproducibility ต่ำ |
| YUM (CentOS/RHEL) | คล้าย APT, package เยอะ | Dependency management ไม่ดีเท่า Nix, reproducibility ต่ำ |
| Homebrew (macOS) | ใช้งานง่าย, package เยอะสำหรับ macOS | Dependency management ดีกว่า APT/YUM แต่ยังไม่เท่า Nix, reproducibility ต่ำ |
เลือกใช้ package manager ตัวไหน ขึ้นอยู่กับความต้องการและความถนัดของแต่ละคน ถ้าต้องการ reproducibility และ dependency management ที่ดี Nix คือตัวเลือกที่ดีที่สุด แต่ถ้าต้องการใช้งานง่ายและมี package เยอะ APT/YUM/Homebrew อาจเป็นตัวเลือกที่ดีกว่า
สมัยผมทำร้านเน็ต SiamCafe เมื่อ 20 กว่าปีก่อน เรื่อง Package Manager นี่แทบไม่มีใครรู้จักเลยครับ ลงโปรแกรมทีนึงก็ลงแบบ manual ล้วนๆ ปวดหัวสุดๆ พอมาเจอ Nix นี่ชีวิตง่ายขึ้นเยอะเลย อยากจะบอกว่า Best Practices ที่ผมเจอมาจากการใช้งานจริง มีดังนี้ครับ
Nix Documentation นี่ค่อนข้างละเอียดเลยครับ ถึงจะยาวหน่อย แต่ควรอ่านให้เข้าใจพื้นฐานก่อน ไม่งั้นจะงงว่าทำไมต้องทำแบบนี้ ทำไมต้องมี store path อะไรพวกนี้ สมัยก่อนผมไม่อ่านนี่มั่วไปหมดเลยครับ เสียเวลามากๆ
Nix Flakes นี่เหมือนเป็น Package Manager อีกชั้นนึง ทำให้จัดการ Dependencies ได้ง่ายขึ้นเยอะเลยครับ ลองคิดภาพตอนทำร้านเน็ต มีคอมหลายสิบเครื่อง แต่ละเครื่องลงโปรแกรมไม่เหมือนกัน ถ้าใช้ Nix Flakes นี่สบายเลยครับ กำหนด config ไว้ที่เดียวแล้ว deploy ไปได้ทุกเครื่อง
{
description = "My awesome project";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { self, nixpkgs }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
in
{
defaultPackage.x86_64-linux = pkgs.hello;
};
}
Code snippet ข้างบนเป็นตัวอย่าง Nix Flake ง่ายๆ ที่บอกว่า project นี้ใช้ package hello จาก nixpkgs-unstable
Nix Expression Language หรือ Nix Language นี่เป็นหัวใจหลักของ Nix เลยครับ มันเป็น Functional Language ที่ใช้เขียน config ต่างๆ ถ้าไม่เข้าใจ Nix Language นี่จะ customize อะไรยากมากครับ ลองเริ่มจากเขียน function ง่ายๆ แล้วค่อยๆ เพิ่มความซับซ้อนไปเรื่อยๆ
ถ้าโปรแกรมที่เราอยากใช้มันไม่มีใน Nixpkgs เราก็สร้าง Package เองได้ครับ ขั้นตอนอาจจะยุ่งยากนิดหน่อย แต่คุ้มค่าแน่นอน เพราะเราจะได้ Package ที่เราควบคุมได้เอง และสามารถ share ให้คนอื่นใช้ได้ด้วย
ถ้าเรา build package อะไรซ้ำๆ กันบนหลายเครื่อง การใช้ Cachix จะช่วยให้ประหยัดเวลาได้เยอะเลยครับ เพราะมันจะเก็บ binary ของ package ที่เรา build ไว้ แล้วเครื่องอื่นๆ สามารถ download ไปใช้ได้เลย ไม่ต้อง build ใหม่ทุกครั้ง
Nix Store ที่เก็บ Package จะใช้ Content-Addressable Storage (CAS) ครับ Path ที่ยาวๆ นั้นคือ Hash ของ Dependencies ทั้งหมดของ Package นั้นๆ ทำให้ Nix สามารถ Guarantee ได้ว่าถ้า Dependencies เปลี่ยน Package ก็จะเปลี่ยนตามไปด้วย
Nix กับ Docker มีเป้าหมายคล้ายกันคือจัดการ Dependencies แต่ Docker จะเน้น Containerization คือการสร้าง environment ที่ isolate จาก host OS ส่วน Nix จะเน้น Reproducibility คือการ Guarantee ว่า build output จะเหมือนเดิมเสมอไม่ว่า build ที่ไหน เมื่อไหร่
Nix เหมาะกับคนที่ต้องการจัดการ Dependencies แบบละเอียด ต้องการ build environment ที่ reproducible และต้องการ share build output ให้คนอื่นใช้ได้ง่ายๆ
Nix Package Manager เป็นเครื่องมือที่ทรงพลังมากครับ ถึงจะเรียนรู้ยากหน่อยในช่วงแรก แต่ถ้าเข้าใจหลักการแล้วจะช่วยให้ชีวิตง่ายขึ้นเยอะเลย โดยเฉพาะคนที่ทำงานด้าน DevOps หรือ System Administration ลองเอาไปปรับใช้กันดูนะครับ รับรองว่าจะติดใจ
ถ้าอยากรู้เรื่อง iCafeForex ลองเข้าไปดูที่ iCafeForex นะครับ
และอย่าลืมแวะไปอ่านบทความอื่นๆ ที่ SiamCafe Blog ด้วยนะครับ