Tìm Hiểu Về Systemd Units và Tệp Đơn Vị trong Linux

Tìm Hiểu Về Systemd Units và Tệp Đơn Vị trong Linux

Ngày càng nhiều bản phân phối Linux chuyển sang sử dụng systemd làm hệ thống khởi động chính. Đây là một bộ công cụ mạnh mẽ, có khả năng quản lý và điều phối các khía cạnh quan trọng của hệ thống, bao gồm dịch vụ, thiết bị gắn ngoài và trạng thái hệ thống.

Trong systemd, khái niệm “unit” đề cập đến bất kỳ tài nguyên nào mà hệ thống có thể nhận diện và quản lý. Các tài nguyên này là đối tượng chính mà systemd có thể điều khiển thông qua các công cụ quản lý của mình. Những tài nguyên này được cấu hình thông qua các tệp tin gọi là unit files.

Bạn đang tìm hiểu về systemd units để quản lý hệ thống Linux? Để triển khai hiệu quả, một VPS giá rẻ chất lượng là lựa chọn tối ưu. Khám phá các gói VPS tại DataOnline với giá chỉ từ 102.000 VNĐ/năm, đảm bảo hiệu suất cao và hỗ trợ 24/7!

Bài viết này sẽ cung cấp cho bạn cái nhìn tổng quan về các loại unit mà systemd có thể xử lý. Chúng tôi cũng sẽ giới thiệu một số chỉ thị (directive) quan trọng trong các tệp unit, giúp bạn tùy chỉnh và quản lý tài nguyên trên hệ thống của mình hiệu quả hơn.

Systemd Units mang lại lợi ích gì cho bạn ?

Các unit là đối tượng mà systemd biết cách quản lý. Về cơ bản, chúng là sự biểu diễn tiêu chuẩn hóa của các tài nguyên hệ thống mà bộ các tiến trình nền (daemon) và các tiện ích đi kèm có thể thao tác được.

Có thể nói rằng các unit tương tự như các dịch vụ hoặc các tác vụ (jobs) trong các hệ thống khởi động khác. Tuy nhiên, khái niệm unit lại mở rộng hơn nhiều, vì chúng có thể được dùng để trừu tượng hóa các dịch vụ, tài nguyên mạng, thiết bị, điểm gắn của hệ thống tập tin, cũng như các nhóm tài nguyên độc lập.

Những ý tưởng mà trong các hệ thống khởi động khác có thể được xử lý thông qua một định nghĩa dịch vụ thống nhất, giờ đây có thể được tách ra thành các unit thành phần theo từng chức năng. Điều này giúp tổ chức theo chức năng, cho phép bạn dễ dàng kích hoạt, tắt hoặc mở rộng tính năng mà không cần phải thay đổi hành vi cốt lõi của một unit.

Một số tính năng mà các unit có thể thực hiện một cách dễ dàng bao gồm:

  • Kích hoạt dựa trên socket: Các socket liên kết với một dịch vụ nên được tách riêng ra khỏi daemon để quản lý độc lập. Điều này mang lại nhiều lợi ích, chẳng hạn như trì hoãn việc khởi động dịch vụ cho đến khi socket liên quan được truy cập lần đầu. Nó cũng cho phép hệ thống tạo tất cả các socket ngay từ đầu trong quá trình khởi động, giúp khởi động các dịch vụ liên quan song song.

  • Kích hoạt dựa trên bus: Các unit cũng có thể được kích hoạt trên giao diện bus do D-Bus cung cấp. Một unit có thể được khởi động khi bus liên quan được xuất bản.

  • Kích hoạt dựa trên đường dẫn: Một unit có thể được khởi động dựa trên hoạt động hoặc sự khả dụng của một số đường dẫn trên hệ thống tập tin. Điều này sử dụng cơ chế inotify.

  • Kích hoạt dựa trên thiết bị: Các unit cũng có thể được khởi động khi phần cứng liên quan xuất hiện lần đầu thông qua sự kiện udev.

  • Ánh xạ phụ thuộc ẩn: Phần lớn cây phụ thuộc cho các unit có thể được systemd tự động xây dựng. Bạn vẫn có thể thêm thông tin về phụ thuộc và thứ tự, nhưng hầu hết công việc nặng đã được hệ thống lo liệu.

  • Instances và templates: Các tệp unit mẫu có thể được sử dụng để tạo ra nhiều instance của cùng một unit chung. Điều này cho phép tạo ra các biến thể nhỏ hoặc các unit “anh chị em” cùng thực hiện chức năng chung.

  • Tăng cường bảo mật dễ dàng: Các unit có thể triển khai các tính năng bảo mật khá tốt chỉ bằng cách thêm một số chỉ thị đơn giản. Ví dụ, bạn có thể chỉ định không hoặc chỉ cho phép quyền đọc tới một phần hệ thống tập tin, giới hạn khả năng của kernel, cũng như phân bổ riêng phần /tmp và quyền truy cập mạng.

  • Drop-ins và snippets: Các unit có thể dễ dàng được mở rộng bằng cách cung cấp các đoạn cấu hình (snippet) sẽ ghi đè lên các phần của tệp unit gốc. Điều này giúp chuyển đổi dễ dàng giữa các cấu hình mặc định và cấu hình được tùy chỉnh.

Có rất nhiều lợi thế mà các unit của systemd mang lại so với các mục công việc trong các hệ thống khởi động khác, nhưng điều trên đủ để bạn hình dung được sức mạnh có thể khai thác thông qua các chỉ thị cấu hình gốc.

Các tệp đơn vị của Systemd được tìm thấy ở đâu ?

Các tệp định nghĩa cách mà systemd sẽ quản lý một unit có thể được tìm thấy ở nhiều vị trí khác nhau, mỗi vị trí có mức độ ưu tiên và ý nghĩa riêng.

  • /lib/systemd/system: Đây là vị trí chứa bản sao của các tệp unit do hệ thống giữ. Khi phần mềm cài đặt các tệp unit trên hệ thống, theo mặc định chúng sẽ được đặt ở đây. Các tệp unit trong thư mục này có thể được khởi động và dừng theo yêu cầu trong một phiên làm việc. Đây chính là tệp unit gốc, thường được viết bởi các maintainer của dự án upstream, và được thiết kế để hoạt động trên bất kỳ hệ thống nào triển khai systemd theo cài đặt chuẩn. Bạn không nên chỉnh sửa các tệp ở đây. Nếu cần thay đổi, hãy ghi đè lên tệp này bằng cách sử dụng một tệp unit ở vị trí khác có mức độ ưu tiên cao hơn.

  • /etc/systemd/system: Nếu bạn muốn thay đổi cách thức hoạt động của một unit, vị trí tốt nhất để thực hiện là trong thư mục này. Các tệp unit ở đây có độ ưu tiên cao hơn so với các vị trí khác trên hệ thống tập tin. Nếu cần thay đổi tệp unit gốc của hệ thống, việc đặt một tệp thay thế tại đây là cách an toàn và linh hoạt nhất.

  • /run/systemd/system: Đây là vị trí dành cho các định nghĩa unit thời gian chạy. Các tệp unit trong thư mục này có ưu tiên nằm giữa /etc/systemd/system và /lib/systemd/system. Các tệp ở đây có trọng số thấp hơn so với /etc/systemd/system nhưng cao hơn so với /lib/systemd/system. Quy trình systemd sử dụng vị trí này cho các tệp unit được tạo động trong thời gian chạy. Thư mục này có thể được dùng để thay đổi hành vi unit của hệ thống cho phiên làm việc hiện tại; tất cả các thay đổi ở đây sẽ bị mất khi khởi động lại máy chủ.

Các loại đơn vị

Systemd phân loại các unit theo loại tài nguyên mà chúng mô tả. Cách dễ nhất để xác định loại của một unit là nhìn vào hậu tố (suffix) của tên tài nguyên. Danh sách sau mô tả các loại unit có sẵn trong systemd:

  • .service: Một unit dịch vụ mô tả cách quản lý một dịch vụ hoặc ứng dụng trên máy chủ. Nó bao gồm cách khởi động hoặc dừng dịch vụ, dưới những hoàn cảnh nào dịch vụ nên được tự động khởi động, cũng như thông tin về phụ thuộc và thứ tự của các phần mềm liên quan.

  • .socket: Một tệp unit socket mô tả một socket mạng hoặc IPC, hoặc một bộ đệm FIFO mà systemd sử dụng cho kích hoạt dựa trên socket. Luôn có một tệp .service liên kết sẽ được khởi động khi có hoạt động trên socket mà unit này định nghĩa.

  • .device: Một unit mô tả một thiết bị được udev hoặc hệ thống tập tin sysfs đánh dấu cần được systemd quản lý. Không phải tất cả các thiết bị đều có tệp .device. Một số trường hợp cần thiết có thể là để sắp xếp thứ tự, gắn và truy cập thiết bị.

  • .mount: Unit này định nghĩa một điểm gắn trên hệ thống để được systemd quản lý. Chúng được đặt tên theo đường dẫn gắn, với các dấu gạch chéo được chuyển thành dấu gạch ngang. Các mục trong /etc/fstab có thể tự động tạo ra các unit tương ứng.

  • .automount: Một unit automount cấu hình một điểm gắn sẽ được tự động gắn. Chúng phải được đặt tên theo điểm gắn mà chúng tham chiếu và phải có một unit .mount tương ứng để định nghĩa chi tiết về gắn kết.

  • .swap: Unit này mô tả không gian swap trên hệ thống. Tên của các unit swap phải phản ánh thiết bị hoặc đường dẫn tệp của không gian swap.

  • .target: Một unit target được sử dụng để tạo ra các điểm đồng bộ cho các unit khác trong quá trình khởi động hoặc thay đổi trạng thái. Chúng cũng có thể được dùng để chuyển hệ thống sang một trạng thái mới. Các unit khác xác định mối quan hệ của chúng với target để gắn kết với hoạt động của target đó.

  • .path: Unit path định nghĩa một đường dẫn trên hệ thống tập tin mà systemd có thể theo dõi để phát hiện thay đổi. Theo mặc định, một unit .service cùng tên sẽ được khởi động khi đường dẫn đạt đến trạng thái chỉ định. Điều này sử dụng cơ chế inotify để giám sát thay đổi của đường dẫn.

  • .timer: Một unit timer định nghĩa một bộ đếm thời gian được quản lý bởi systemd, tương tự như một công việc cron để kích hoạt trễ hoặc theo lịch trình. Một unit tương ứng sẽ được khởi động khi timer đạt đến thời điểm chỉ định.

  • .snapshot: Một unit snapshot được tạo tự động bởi lệnh systemctl snapshot. Nó cho phép bạn tái tạo lại trạng thái hiện tại của hệ thống sau khi có thay đổi. Các snapshot không tồn tại qua các phiên làm việc và được dùng để quay lại trạng thái tạm thời.

  • .slice: Một unit slice liên kết với các nút Control Group của Linux, cho phép hạn chế hoặc phân bổ tài nguyên cho các tiến trình thuộc slice đó. Tên của slice phản ánh vị trí phân cấp trong cây cgroup. Các unit được đặt vào các slice nhất định theo mặc định tùy theo loại của chúng.

  • .scope: Các unit scope được tạo tự động bởi systemd từ thông tin nhận được từ các giao diện bus của nó. Chúng được dùng để quản lý các tập hợp tiến trình hệ thống được tạo ra từ bên ngoài.

Như bạn có thể thấy, có rất nhiều loại unit khác nhau mà systemd có thể quản lý. Nhiều loại unit có thể hoạt động phối hợp với nhau để cung cấp các tính năng mở rộng; ví dụ, một số unit có thể được dùng để kích hoạt các unit khác và cung cấp chức năng kích hoạt.

Chúng ta sẽ chủ yếu tập trung vào các unit .service vì tính tiện dụng và sự nhất quán trong việc quản lý chúng của các quản trị viên hệ thống.

Cấu trúc của một tệp đơn vị

Cấu trúc nội bộ của các tệp unit được tổ chức thành các phần (sections). Mỗi phần được đánh dấu bằng cặp dấu ngoặc vuông “[” và “]” với tên phần được ghi bên trong. Mỗi phần kéo dài cho đến khi gặp phần kế tiếp hoặc đến cuối tệp.

Đặc điểm chung của các tệp đơn vị

  • Tên các phần được định nghĩa rõ ràng và có phân biệt chữ hoa chữ thường. Ví dụ, phần [Unit] sẽ không được hiểu đúng nếu viết là [UNIT].

  • Nếu bạn cần thêm các phần không chuẩn để các ứng dụng ngoài systemd phân tích, bạn có thể thêm tiền tố X- vào tên phần.

  • Bên trong các phần này, hành vi và metadata của unit được định nghĩa qua các chỉ thị (directive) theo định dạng key-value, với dấu bằng dùng để gán giá trị, như ví dụ:

    [Section]
    Directive1=value
    Directive2=value
    
    . . .
  • Trong trường hợp của file override (ví dụ như trong thư mục unit có hậu tố .d), các chỉ thị có thể được đặt lại bằng cách gán cho chúng chuỗi rỗng. Ví dụ, tệp unit gốc có thể chứa:

    Directive1=default_value

    Để loại bỏ giá trị mặc định trong file override, bạn chỉ cần tham chiếu Directive1 mà không gán giá trị:

    Directive1=

Nhìn chung, systemd cho phép cấu hình dễ dàng và linh hoạt. Ví dụ, nó chấp nhận nhiều biểu thức boolean khác nhau (1, yes, on, true cho giá trị đúng và 0, no, off, false cho giá trị sai). Thời gian cũng được phân tích một cách thông minh, với giá trị không có đơn vị mặc định được hiểu là giây, và hỗ trợ kết hợp nhiều định dạng nội bộ.

Các chỉ thị trong phần

Phần đầu tiên trong hầu hết các tệp unit là phần [Unit]. Phần này thường được dùng để định nghĩa metadata cho unit và cấu hình mối quan hệ của unit với các unit khác.

Mặc dù thứ tự các phần không ảnh hưởng đến quá trình phân tích của systemd, nhưng phần này thường được đặt ở đầu vì nó cung cấp cái nhìn tổng quan về unit. Một số chỉ thị phổ biến trong phần [Unit] bao gồm:

  • Description=: Chỉ thị này được dùng để mô tả tên và chức năng cơ bản của unit. Nó sẽ được các công cụ của systemd hiển thị, vì vậy nên được đặt một mô tả ngắn gọn, cụ thể và có tính thông tin.

  • Documentation=: Chỉ thị này cung cấp địa chỉ (URI) cho tài liệu hướng dẫn, có thể là trang man nội bộ hoặc URL truy cập qua web. Lệnh systemctl status sẽ hiển thị thông tin này, giúp dễ dàng tra cứu.

  • Requires=: Liệt kê các unit mà unit hiện tại phụ thuộc cơ bản. Nếu unit này được kích hoạt, các unit được liệt kê phải khởi động thành công, nếu không unit sẽ thất bại. Các unit này được khởi động song song với unit hiện tại theo mặc định.

  • Wants=: Tương tự như Requires=, nhưng ít nghiêm ngặt hơn. Systemd sẽ cố gắng khởi động các unit được liệt kê khi unit hiện tại kích hoạt. Nếu các unit đó không tồn tại hoặc khởi động thất bại, unit hiện tại vẫn tiếp tục hoạt động. Đây là cách cấu hình phụ thuộc được khuyến nghị.

  • BindsTo=: Chỉ thị này tương tự như Requires=, nhưng còn khiến unit hiện tại dừng khi unit liên quan kết thúc.

  • Before=: Các unit liệt kê trong chỉ thị này sẽ không được khởi động cho đến khi unit hiện tại được đánh dấu là đã khởi động, nếu chúng cùng được kích hoạt. Chỉ thị này không tự nó tạo ra mối quan hệ phụ thuộc mà cần kết hợp với các chỉ thị khác.

  • After=: Các unit liệt kê sẽ được khởi động trước khi khởi động unit hiện tại. Tuy nhiên, chỉ thị này không tự nó tạo ra mối quan hệ phụ thuộc; nếu cần phải thiết lập phụ thuộc, cần kết hợp với các chỉ thị ở trên.

  • Conflicts=: Dùng để liệt kê các unit không thể chạy đồng thời với unit hiện tại. Khi một unit có mối quan hệ này được khởi động, các unit bị xung đột sẽ bị dừng.

  • Condition…=: Có nhiều chỉ thị bắt đầu bằng “Condition” cho phép quản trị viên kiểm tra một số điều kiện trước khi khởi động unit. Điều này giúp cung cấp một tệp unit chung chỉ chạy trên các hệ thống phù hợp. Nếu điều kiện không được đáp ứng, unit sẽ bị bỏ qua một cách nhẹ nhàng.

  • Assert…=: Tương tự như các chỉ thị bắt đầu bằng “Condition”, nhưng nếu điều kiện không được đáp ứng thì unit sẽ báo lỗi.

Bằng cách sử dụng các chỉ thị này và một số chỉ thị khác, bạn có thể xác lập thông tin chung về unit cũng như mối quan hệ của nó với các unit khác và hệ điều hành.

Phía bên kia của tệp unit, phần cuối thường là phần [Install]. Phần này là tùy chọn và được dùng để định nghĩa hành vi của một unit khi nó được kích hoạt (enabled) hoặc tắt (disabled). Kích hoạt một unit có nghĩa là đánh dấu nó sẽ tự động khởi động khi hệ thống khởi động. Điều này thực hiện bằng cách gắn unit đó vào một unit khác nằm trong chuỗi các unit khởi động.

Chỉ có những unit có thể được kích hoạt mới có phần này. Các chỉ thị trong phần này định nghĩa hành động khi unit được kích hoạt:

  • WantedBy=: Đây là chỉ thị phổ biến nhất để xác định cách kích hoạt một unit. Nó cho phép bạn chỉ định một mối quan hệ phụ thuộc tương tự như chỉ thị Wants= trong phần [Unit]. Sự khác biệt là chỉ thị này được đưa vào tệp phụ trợ, cho phép unit chính được giữ nguyên sạch sẽ. Khi một unit có chỉ thị này được kích hoạt, một thư mục sẽ được tạo trong /etc/systemd/system với tên tương ứng và hậu tố .wants. Bên trong thư mục đó sẽ có một liên kết tượng trưng (symbolic link) đến unit hiện tại, tạo ra mối quan hệ phụ thuộc. Ví dụ, nếu unit hiện tại có WantedBy=multi-user.target, một thư mục tên multi-user.target.wants sẽ được tạo ra (nếu chưa có) và bên trong sẽ có liên kết đến unit này. Tắt unit sẽ xóa liên kết đó và hủy bỏ mối quan hệ phụ thuộc.

  • RequiredBy=: Tương tự như WantedBy=, nhưng chỉ định phụ thuộc bắt buộc; nếu điều kiện không được đáp ứng thì việc kích hoạt sẽ thất bại. Khi kích hoạt, unit có chỉ thị này sẽ tạo ra một thư mục có hậu tố .requires.

  • Alias=: Chỉ thị này cho phép unit được kích hoạt dưới một tên khác. Điều này giúp cung cấp nhiều lựa chọn nhà cung cấp chức năng, sao cho các unit liên quan có thể tìm kiếm bất kỳ nhà cung cấp nào của tên chung được ủy quyền.

  • Also=: Chỉ thị này cho phép kích hoạt hoặc tắt một nhóm các unit cùng lúc. Các unit hỗ trợ mà luôn cần có khi unit chính hoạt động có thể được liệt kê ở đây và sẽ được quản lý như một nhóm khi thực hiện các tác vụ cài đặt.

  • DefaultInstance=: Đối với các unit template (sẽ được đề cập sau) có thể tạo ra các instance với tên không xác định trước, chỉ thị này được dùng làm giá trị mặc định nếu không cung cấp tên phù hợp.

Các chỉ thị riêng cho từng loại đơn vị

Nằm giữa hai phần trên, bạn có thể gặp các phần dành riêng cho loại unit cụ thể. Hầu hết các loại unit đều có những chỉ thị chỉ áp dụng cho loại của chúng và được đặt trong các phần có tên tương ứng. Một số loại unit như device, target, snapshotscope không có chỉ thị riêng, do đó không có phần đặc thù cho chúng.

Phần [Service]

Phần [Service] được dùng để cung cấp cấu hình chỉ áp dụng cho dịch vụ (service). Một trong những thông tin cơ bản cần được chỉ định trong phần này là Type= của dịch vụ. Chỉ thị này phân loại dịch vụ theo cách thức xử lý tiến trình và hành vi daemon hóa, điều này rất quan trọng vì nó cho systemd biết cách quản lý dịch vụ một cách chính xác và xác định trạng thái của nó.

Chỉ thị Type= có thể nhận các giá trị sau:

  • simple: Dịch vụ có tiến trình chính được chỉ định trực tiếp trong lệnh khởi động. Đây là giá trị mặc định nếu không đặt Type=BusName=, nhưng có chỉ định ExecStart=. Mọi giao tiếp sẽ được xử lý bên ngoài unit này qua một unit khác phù hợp (ví dụ như thông qua một unit .socket nếu dịch vụ cần giao tiếp qua socket).

  • forking: Dịch vụ này dùng khi tiến trình fork một tiến trình con, và tiến trình cha thoát ngay sau đó. Chỉ thị này báo cho systemd rằng tiến trình chính vẫn đang chạy mặc dù tiến trình cha đã thoát.

  • oneshot: Chỉ thị này chỉ ra rằng tiến trình sẽ chạy trong thời gian ngắn và systemd cần chờ cho đến khi tiến trình kết thúc trước khi tiếp tục với các unit khác. Đây là giá trị mặc định nếu không có chỉ định Type=ExecStart=. Nó được dùng cho các tác vụ một lần.

  • dbus: Chỉ thị này chỉ ra rằng unit sẽ chiếm một tên trên bus của D-Bus. Khi điều này xảy ra, systemd sẽ tiếp tục xử lý unit tiếp theo.

  • notify: Chỉ thị này chỉ ra rằng dịch vụ sẽ gửi thông báo khi đã khởi động xong. Quá trình systemd sẽ chờ cho đến khi nhận được thông báo này trước khi tiến hành các unit khác.

  • idle: Chỉ thị này cho biết dịch vụ sẽ không chạy cho đến khi tất cả các job được xếp hàng xử lý xong.

Một số chỉ thị bổ sung có thể cần thiết cho một số loại dịch vụ nhất định, ví dụ:

  • RemainAfterExit=: Chỉ thị này thường được sử dụng với dịch vụ oneshot. Nó chỉ ra rằng dịch vụ vẫn được coi là hoạt động ngay cả khi tiến trình đã kết thúc.

  • PIDFile=: Nếu dịch vụ có loại “forking”, chỉ thị này dùng để chỉ định đường dẫn của tệp chứa số ID tiến trình của tiến trình con chính cần được giám sát.

  • BusName=: Chỉ thị này nên được thiết lập thành tên bus của D-Bus mà dịch vụ cố gắng chiếm khi dùng loại dịch vụ “dbus”.

  • NotifyAccess=: Chỉ thị này quy định quyền truy cập vào socket được dùng để lắng nghe thông báo khi chọn loại dịch vụ “notify”. Giá trị có thể là “none”, “main”, hoặc “all”. Mặc định “none” nghĩa là bỏ qua tất cả thông báo trạng thái; “main” chỉ lắng nghe thông báo từ tiến trình chính; “all” sẽ xử lý tất cả thông báo từ thành viên của nhóm điều khiển dịch vụ.

Như đã thảo luận, chúng ta đã đề cập một số thông tin cơ bản, nhưng chưa nói đến cách quản lý dịch vụ. Các chỉ thị để quản lý dịch vụ bao gồm:

  • ExecStart=: Chỉ định đường dẫn đầy đủ và các đối số của lệnh để khởi động tiến trình. Chỉ có thể chỉ định một lần (ngoại trừ các dịch vụ oneshot). Nếu đường dẫn được đặt trước bởi ký tự “-”, các trạng thái thoát khác 0 sẽ được chấp nhận mà không đánh dấu unit là thất bại.

  • ExecStartPre=: Dùng để cung cấp các lệnh bổ sung cần thực thi trước khi tiến trình chính được khởi động. Có thể sử dụng nhiều lần. Các lệnh này cũng cần chỉ định đường dẫn đầy đủ và có thể được đặt trước bởi “-” để chỉ ra rằng thất bại của lệnh sẽ được chấp nhận.

  • ExecStartPost=: Tương tự như ExecStartPre= nhưng các lệnh sẽ được chạy sau khi tiến trình chính khởi động.

  • ExecReload=: Chỉ thị tùy chọn cho biết lệnh cần thiết để tải lại cấu hình của dịch vụ nếu có.

  • ExecStop=: Chỉ thị cho biết lệnh cần thiết để dừng dịch vụ. Nếu không chỉ định, tiến trình sẽ bị giết ngay khi dịch vụ bị dừng.

  • ExecStopPost=: Dùng để chỉ định các lệnh thực thi sau lệnh dừng dịch vụ.

  • RestartSec=: Nếu dịch vụ được cấu hình tự động khởi động lại, chỉ thị này xác định thời gian chờ trước khi thử khởi động lại.

  • Restart=: Chỉ định các trường hợp mà systemd sẽ tự động khởi động lại dịch vụ. Giá trị có thể là “always”, “on-success”, “on-failure”, “on-abnormal”, “on-abort”, hoặc “on-watchdog”. Các giá trị này kích hoạt việc khởi động lại tùy theo cách dịch vụ bị dừng.

  • TimeoutSec=: Cấu hình khoảng thời gian systemd sẽ chờ khi dừng hoặc khởi động dịch vụ trước khi đánh dấu là thất bại hoặc buộc dừng tiến trình. Bạn cũng có thể thiết lập riêng các timeout với TimeoutStartSec=TimeoutStopSec=.

Phần [Socket]

Các unit socket rất phổ biến trong cấu hình systemd vì nhiều dịch vụ áp dụng cơ chế kích hoạt dựa trên socket để tăng cường khả năng song song và sự linh hoạt. Mỗi unit socket phải có một unit dịch vụ tương ứng sẽ được kích hoạt khi socket nhận được hoạt động.

Bằng cách tách phần điều khiển socket ra khỏi chính dịch vụ, các socket có thể được khởi tạo sớm và các dịch vụ liên quan có thể khởi động song song. Theo mặc định, tên của socket sẽ cố gắng khởi động dịch vụ cùng tên khi có kết nối. Khi dịch vụ được khởi động, socket sẽ được chuyển giao để xử lý các yêu cầu đang chờ.

Các chỉ thị thường dùng để định nghĩa socket bao gồm:

  • ListenStream=: Định nghĩa địa chỉ cho một socket kiểu stream, hỗ trợ giao tiếp theo trình tự và đáng tin cậy. Các dịch vụ sử dụng TCP nên dùng loại socket này.

  • ListenDatagram=: Định nghĩa địa chỉ cho một socket kiểu datagram, hỗ trợ giao tiếp nhanh nhưng không đảm bảo độ tin cậy. Các dịch vụ sử dụng UDP nên dùng loại này.

  • ListenSequentialPacket=: Định nghĩa địa chỉ cho giao tiếp theo trình tự, đáng tin cậy với các datagram có độ dài tối đa và giữ nguyên ranh giới thông điệp. Loại này thường gặp với các Unix socket.

  • ListenFIFO=: Bên cạnh các kiểu socket lắng nghe khác, bạn cũng có thể chỉ định một bộ đệm FIFO thay cho socket.

Các chỉ thị bổ sung để kiểm soát đặc tính của socket:

  • Accept=: Quy định liệu có tạo thêm instance của dịch vụ cho mỗi kết nối hay không. Nếu đặt là false (mặc định), một instance sẽ xử lý tất cả các kết nối.

  • SocketUser=: Đối với Unix socket, chỉ định chủ sở hữu của socket. Nếu không thiết lập, mặc định là root.

  • SocketGroup=: Đối với Unix socket, chỉ định nhóm sở hữu của socket. Nếu không thiết lập, mặc định là nhóm root. Nếu chỉ có SocketUser= được đặt, systemd sẽ cố gắng tìm nhóm tương ứng.

  • SocketMode=: Đối với Unix socket hoặc FIFO, xác định quyền trên đối tượng được tạo ra.

  • Service=: Nếu tên của dịch vụ không khớp với tên của socket, dịch vụ có thể được chỉ định qua chỉ thị này.

Phần [Mount]

Các unit mount cho phép quản lý điểm gắn (mount point) từ bên trong systemd. Các điểm gắn được đặt tên dựa trên thư mục mà chúng quản lý, với thuật toán chuyển đổi được áp dụng:

  • Ví dụ, dấu gạch chéo đầu tiên sẽ được loại bỏ, các dấu gạch chéo khác sẽ được chuyển thành dấu gạch ngang “-”, và tất cả các dấu gạch và ký tự không in được sẽ được thay thế bằng mã escape kiểu C. Kết quả của chuyển đổi này được dùng làm tên unit mount.

  • Các unit mount thường được chuyển trực tiếp từ các mục trong /etc/fstab trong quá trình khởi động. Đối với các định nghĩa unit tự động tạo và các tệp unit mà bạn muốn định nghĩa, các chỉ thị sau rất hữu ích:

    • What=: Đường dẫn tuyệt đối đến tài nguyên cần gắn.

    • Where=: Đường dẫn tuyệt đối của điểm gắn nơi tài nguyên sẽ được gắn. Nó nên giống với tên tệp unit, chỉ khác ở cách biểu diễn đường dẫn chuẩn của hệ thống tập tin.

    • Type=: Loại hệ thống tập tin của điểm gắn.

    • Options=: Các tùy chọn mount cần áp dụng, được phân cách bằng dấu phẩy.

    • SloppyOptions=: Giá trị boolean quyết định liệu mount có thất bại nếu có tùy chọn không nhận diện được hay không.

    • DirectoryMode=: Nếu cần tạo các thư mục cha cho điểm gắn, chỉ định quyền của các thư mục đó.

    • TimeoutSec=: Cấu hình khoảng thời gian chờ của hệ thống cho đến khi thao tác gắn được đánh dấu là thất bại.

The [Automount] Section

Unit automount cho phép một unit .mount liên quan được tự động gắn khi hệ thống khởi động. Tương tự như unit mount, các unit này phải được đặt tên theo đường dẫn đã được chuyển đổi.

Phần [Automount] khá đơn giản với chỉ có hai tùy chọn:

  • Where=: Đường dẫn tuyệt đối của điểm tự động gắn trên hệ thống tập tin. Nó sẽ khớp với tên tệp, chỉ khác ở cách biểu diễn đường dẫn chuẩn.

  • DirectoryMode=: Nếu điểm tự động gắn hoặc bất kỳ thư mục cha nào cần được tạo, chỉ định quyền cho các thành phần của đường dẫn đó.

Phần Automount

Các unit swap được sử dụng để cấu hình không gian swap trên hệ thống. Tên của các unit swap phải phản ánh tệp swap hoặc thiết bị swap, sử dụng cùng thuật toán chuyển đổi hệ thống tập tin như đã nêu ở trên.

Tương tự như các tùy chọn mount, các unit swap có thể được tạo tự động từ các mục trong /etc/fstab hoặc có thể được cấu hình thông qua tệp unit riêng biệt. Phần [Swap] có thể chứa các chỉ thị sau:

  • What=: Đường dẫn tuyệt đối đến vị trí của không gian swap, có thể là tệp hoặc thiết bị.

  • Priority=: Số nguyên chỉ định mức độ ưu tiên của không gian swap được cấu hình.

  • Options=: Các tùy chọn thường được thiết lập trong /etc/fstab có thể được đặt ở đây dưới dạng danh sách các giá trị phân cách bởi dấu phẩy.

  • TimeoutSec=: Khoảng thời gian systemd chờ đợi cho đến khi swap được kích hoạt trước khi đánh dấu là thất bại.

Phần [Path]

Một unit path định nghĩa một đường dẫn trên hệ thống tập tin mà systemd có thể theo dõi để phát hiện thay đổi. Một unit khác phải tồn tại và được kích hoạt khi có hoạt động nhất định tại đường dẫn đó. Hoạt động của đường dẫn được xác định thông qua các sự kiện inotify.

Phần [Path] có thể chứa các chỉ thị sau:

  • PathExists=: Kiểm tra xem đường dẫn có tồn tại hay không. Nếu có, unit liên quan sẽ được kích hoạt.

  • PathExistsGlob=: Tương tự như trên, nhưng hỗ trợ các biểu thức glob (mẫu khớp tệp).

  • PathChanged=: Theo dõi thay đổi tại đường dẫn. Unit liên quan sẽ được kích hoạt khi phát hiện sự thay đổi sau khi tệp được đóng.

  • PathModified=: Giám sát thay đổi tương tự như PathChanged, nhưng kích hoạt khi tệp được ghi (write) cũng như khi tệp được đóng.

  • DirectoryNotEmpty=: Cho phép systemd kích hoạt unit liên quan khi thư mục không còn trống.

  • Unit=: Chỉ định unit sẽ được kích hoạt khi các điều kiện đường dẫn ở trên được đáp ứng. Nếu không được chỉ định, systemd sẽ tìm kiếm một tệp .service cùng tên với unit này.

  • MakeDirectory=: Quy định liệu systemd có tự động tạo cấu trúc thư mục cho đường dẫn trước khi theo dõi hay không.

  • DirectoryMode=: Nếu trên được kích hoạt, chỉ định quyền cho các thành phần của đường dẫn được tạo.

Phần [Timer]

Các unit timer được dùng để lên lịch các tác vụ hoạt động vào một thời điểm cụ thể hoặc sau một khoảng thời gian trễ nhất định. Loại unit này thay thế hoặc bổ sung một số chức năng của daemon cron hoặc at. Một unit tương ứng phải được cung cấp và sẽ được kích hoạt khi bộ đếm thời gian đạt đến thời điểm chỉ định.

Phần [Timer] có thể chứa các chỉ thị sau:

  • OnActiveSec=: Cho phép kích hoạt unit liên quan dựa trên thời gian tính từ khi unit timer được kích hoạt.

  • OnBootSec=: Xác định khoảng thời gian sau khi hệ thống khởi động mà unit liên quan nên được kích hoạt.

  • OnStartupSec=: Tương tự như trên, nhưng tính từ khi tiến trình systemd bắt đầu.

  • OnUnitActiveSec=: Đặt bộ đếm thời gian dựa trên thời điểm unit liên quan được kích hoạt lần cuối.

  • OnUnitInactiveSec=: Đặt bộ đếm thời gian dựa trên thời điểm unit liên quan được đánh dấu là không hoạt động lần cuối.

  • OnCalendar=: Cho phép kích hoạt unit liên quan bằng cách chỉ định một thời điểm tuyệt đối thay vì tính tương đối với một sự kiện.

  • AccuracySec=: Chỉ định độ chính xác mà timer nên tuân theo. Mặc định, unit liên quan sẽ được kích hoạt trong vòng một phút sau khi timer đạt đến thời điểm. Giá trị của chỉ thị này xác định giới hạn trên của khoảng thời gian mà systemd lên lịch kích hoạt.

  • Unit=: Chỉ thị này dùng để xác định unit sẽ được kích hoạt khi timer hết hạn. Nếu không được thiết lập, systemd sẽ tìm một unit .service có tên khớp với unit timer.

  • Persistent=: Nếu được đặt, systemd sẽ kích hoạt unit liên quan ngay khi timer kích hoạt nếu nó đã bị bỏ lỡ trong thời gian timer không hoạt động.

  • WakeSystem=: Chỉ thị này cho phép đánh thức hệ thống từ chế độ ngủ nếu timer đạt đến thời điểm khi hệ thống đang ở trạng thái ngủ.

Phần [Slice]

Phần [Slice] của một tệp unit thực chất không có cấu hình riêng dành cho unit slice. Thay vào đó, nó có thể chứa các chỉ thị quản lý tài nguyên mà cũng có thể áp dụng cho một số loại unit khác đã đề cập ở trên. Một số chỉ thị phổ biến có thể dùng trong phần [Slice] (và cũng có thể sử dụng ở các phần khác như [Scope], [Service], [Socket], [Mount], [Swap]) được mô tả chi tiết trong trang man systemd.resource-control.

Tạo các đơn vị thể hiện từ các tệp đơn vị mẫu

Ở phần trước, chúng ta đã nhắc đến ý tưởng rằng các tệp unit mẫu (template) có thể được dùng để tạo ra nhiều instance của unit. Trong phần này, chúng ta sẽ đi sâu hơn vào khái niệm đó.

Tên của đơn vị mẫu và đơn vị thể hiện

Các tệp unit mẫu có thể được nhận diện bởi ký hiệu “@” xuất hiện sau tên unit gốc và trước hậu tố kiểu unit. Ví dụ, một tệp unit mẫu có tên:

example@.service

Khi tạo một instance từ tệp mẫu, một định danh instance sẽ được chèn vào giữa ký hiệu “@” và dấu chấm bắt đầu phần hậu tố kiểu unit. Ví dụ, tệp mẫu trên có thể tạo ra một unit instance có tên:

example@instance1.service

Thông thường, một tệp instance được tạo ra dưới dạng liên kết tượng trưng (symbolic link) trỏ về tệp mẫu, với tên liên kết bao gồm định danh instance. Khi quản lý một instance unit, systemd sẽ tìm kiếm một tệp có tên instance chính xác như bạn đã chỉ định. Nếu không tìm thấy, nó sẽ tìm tệp mẫu tương ứng.

Bộ định danh mẫu

Sức mạnh của các tệp unit mẫu chủ yếu được thể hiện qua khả năng thay thế động thông tin phù hợp trong định nghĩa unit theo môi trường hoạt động. Điều này được thực hiện bằng cách đặt các chỉ thị trong tệp mẫu như bình thường, nhưng thay thế một số giá trị hoặc một phần của giá trị bằng các biến ký hiệu (specifier). Một số ký hiệu thông dụng được thay thế khi một instance unit được diễn giải bao gồm:

  • %n: Ở bất cứ đâu xuất hiện ký hiệu này trong tệp mẫu, tên đầy đủ của unit kết quả sẽ được chèn vào.

  • %N: Tương tự như %n, nhưng sẽ đảo ngược bất kỳ ký tự escape nào (ví dụ như trong các mẫu đường dẫn).

  • %p: Tham chiếu đến tiền tố của tên unit, tức là phần tên unit trước ký hiệu “@”.

  • %P: Tương tự như %p nhưng đảo ngược các ký tự escape.

  • %i: Tham chiếu đến tên instance, tức là định danh xuất hiện sau “@” trong tên instance. Đây là ký hiệu được sử dụng phổ biến nhất vì nó luôn mang giá trị động. Ví dụ, nếu định danh của instance là cổng mà dịch vụ sẽ chạy, tệp mẫu có thể sử dụng ký hiệu này để đặt cấu hình cho cổng.

  • %I: Tương tự như %i nhưng đảo ngược các ký tự escape.

  • %f: Sẽ được thay thế bằng tên instance chưa bị escape hoặc tên tiền tố, được ghép thêm dấu “/” ở đầu.

  • %c: Chỉ ra control group của unit, với cấu trúc phân cấp cha tiêu chuẩn của /sys/fs/cgroup/systemd/ bị loại bỏ.

  • %u: Tên của người dùng được cấu hình để chạy unit.

  • %U: Tương tự như %u nhưng dưới dạng số UID thay vì tên.

  • %H: Tên của host của hệ thống đang chạy unit.

  • %%: Dùng để chèn một dấu phần trăm (%) theo nghĩa đen.

Bằng cách sử dụng các ký hiệu trên trong tệp mẫu, systemd sẽ tự động điền các giá trị đúng khi diễn giải mẫu để tạo ra một instance unit.

Kết luận

Khi làm việc với systemd, hiểu biết về các unit và tệp unit sẽ giúp công việc quản trị trở nên dễ dàng hơn. Khác với nhiều hệ thống khởi động khác, bạn không cần phải biết một ngôn ngữ lập trình để giải thích các tệp khởi động dùng để khởi động dịch vụ hay hệ thống. Các tệp unit sử dụng cú pháp khai báo khá đơn giản, cho phép bạn nhìn vào nhanh chóng mục đích và tác động của một unit khi được kích hoạt.

Hiểu rõ tệp đơn vị giúp bạn tối ưu hóa hệ thống Linux. Nếu cần môi trường thực hành ổn định, hãy thuê VPS tại DataOnline. Với băng thông không giới hạn và uptime 99,9%, VPS của chúng tôi là giải pháp lý tưởng cho mọi dự án của bạn!

Việc tách rời logic kích hoạt thành các unit riêng biệt không chỉ giúp các tiến trình nội bộ của systemd tối ưu hóa việc khởi động song song, mà còn giữ cho cấu hình trở nên đơn giản và cho phép bạn sửa đổi, khởi động lại một số unit mà không cần phá vỡ hay tái tạo lại các kết nối liên quan. Việc tận dụng các khả năng này sẽ mang lại cho bạn sự linh hoạt và sức mạnh lớn hơn trong công tác quản trị.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *