Friday, 30 June 2017

systemd là gì

$ whatis systemd
systemd (1)          - systemd system and service manager

systemd thuộc nhóm chương trình: system and service manager - nó quản lý (bật/tắt/khởi động lại...) các dịch vụ chạy trên máy từ lúc bật máy cho đến lúc tắt máy. Nó cũng quản lý luôn cả hệ thống (system) cụ thể là các công việc: set tên máy (hostname), cấu hình loopback interface (lo trong output của lệnh `ip addr`), thiết lập và mount các filesystem như /sys /proc ...

systemd thường là process đầu tiên được chạy sau khi bật máy (có PID = 1) và còn được gọi là init system. Các chương trình khác cùng loại có thể kể tới Upstart (trên Ubuntu đến bản 14.04), launchd của OSX, supervisor viết bằng Python, sysV là hệ thống init cổ điển viết bằng shell script...

Việc chuyển sang systemd là quyết định của Debian - distro mà Ubuntu dựa vào, vậy nên Ubuntu đã phải tiếc nuối bỏ đi đứa con ruột của mình là Upstart với một bài viết mạnh mẽ đầy nước mắt của founder Ubuntu




Không bàn cãi thêm về chuyện hơn thua, ta vẫn phải tiếp tục tiến về phía trước với Systemd.

## Các khái niệm của systemd

systemd quản lý các "unit"

Mỗi unit sẽ được cấu hình trong một unit file, thường nằm trong thư mục:

/etc/systemd/system: các file config do người dùng thêm
/lib/systemd/system: các unit file do các phần mềm cài vào (VD cài NGINX, nếu package NGINX có chứa file unit thì nó sẽ được cho vào đây)
/run/systemd/system: runtime units

Có 12 loại unit khác nhau, nhưng ta sẽ chỉ quan tâm đến loại "service", là unit sẽ quản lý một chương trình khởi động khi bật máy và luôn luôn chạy ở chế độ "nền" (background) và được gọi là daemon.


## Systemctl - điều khiển systemd

systemctl là câu lệnh để giám sát và điều khiển systemd (ctl = control), cụ thể nó sẽ tương tác với các unit.

### Liệt kê các unit đã được load


```
$ systemctl list-units | tail  -n2 # chỉ xem 2 dòng cuối
164 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
```

Kết quả khá nhiều (164), bao gồm tất cả 12 loại unit.
`list-units` là câu lệnh mặc định được chạy khi ta chỉ gõ `systemctl` vì vậy không cần gõ `list-units`.
Để chỉ hiện service unit, thêm `-t service`

```
 $ systemctl -t service | head -n3 # chỉ hiện 3 dòng đầu
UNIT                                                LOAD   ACTIVE SUB     DESCRIPTION
accounts-daemon.service                             loaded active running Accounts Service
acpid.service                                       loaded active running ACPI event daemon

```

### Hiển thị trạng thái của hệ thống


```
$ systemctl status
● fmlug
    State: degraded
     Jobs: 0 queued
   Failed: 1 units
    Since: T6 2017-06-30 09:23:05 ICT; 2h 24min ago
   CGroup: /
           ├─user.slice
           │ └─user-1000.slice
           │   ├─user@1000.service
...
```

(bấm q để thoát).

Output thân thiện với người đọc, vẽ ra cây các  các process đang chạy kèm theo service ứng với nó nếu có.
Nếu cần output thân thiện với chương trình khác, dùng lệnh `systemctl show`.

Khi thêm tên của unit hay PID, output sẽ hiển thị các thông tin về process đó. Ví dụ hiển thị thông tin về cron service (PID, câu lệnh, log gần nhất...):

```
$ systemctl status cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
   Active: active (running) since T6 2017-06-30 09:23:06 ICT; 2h 28min ago
     Docs: man:cron(8)
 Main PID: 550 (cron)
   CGroup: /system.slice/cron.service
           └─550 /usr/sbin/cron -f

Th06 30 09:23:06 fmlug systemd[1]: Started Regular background program processing daemon.
Th06 30 09:23:06 fmlug cron[550]: (CRON) INFO (pidfile fd = 3)
Th06 30 09:23:06 fmlug cron[550]: (CRON) INFO (Running @reboot jobs)
Th06 30 10:17:01 fmlug CRON[4748]: pam_unix(cron:session): session opened for user root by (uid=0)
Th06 30 10:17:01 fmlug CRON[4749]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Th06 30 10:17:01 fmlug CRON[4748]: pam_unix(cron:session): session closed for user root
Th06 30 11:17:01 fmlug CRON[7647]: pam_unix(cron:session): session opened for user root by (uid=0)
Th06 30 11:17:01 fmlug CRON[7648]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Th06 30 11:17:01 fmlug CRON[7647]: pam_unix(cron:session): session closed for user root

```

### Điều khiển một service:

Bật, tắt, reload, restart - những câu lệnh bạn sẽ dùng nhiều nhất để điều khiển 1 service

```
# systemctl start cron # sẽ không có ouput nào cả
# systemctl status cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor prese
   Active: active (running) since T6 2017-06-30 12:01:19 ICT; 5s ago
# systemctl stop cron
# systemctl status cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor prese
   Active: inactive (dead) since T6 2017-06-30 12:02:03 ICT; 1s ago

# systemctl restart cron
# systemctl status cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor prese
   Active: active (running) since T6 2017-06-30 12:12:25 ICT; 2s ago
     Docs: man:cron(8)
 Main PID: 10085 (cron)
   CGroup: /system.slice/cron.service
           └─10085 /usr/sbin/cron -f

Th06 30 12:12:25 fmlug systemd[1]: Stopped Regular background program proc
Th06 30 12:12:25 fmlug systemd[1]: Started Regular background program proc
Th06 30 12:12:25 fmlug cron[10085]: (CRON) INFO (pidfile fd = 3)
Th06 30 12:12:25 fmlug cron[10085]: (CRON) INFO (Skipping @reboot jobs --
```

`start` bật (activate) một unit, chuyển state của nó thành `active(running)`,
`stop` tắt (deactivate) một unit, chuyển state của nó thành jj`inactive (dead)`.
`restart` chạy `stop` rồi `start` unit.

`reload` sẽ thử yêu cầu service load lại config của mình, nếu service đó hỗ trợ, nó sẽ thử reload (vd NGINX/Apache có khả năng reload config). Còn nếu không, câu lệnh sẽ báo lỗi:

```
# systemctl reload cron
Failed to reload cron.service: Job type reload is not applicable for unit cron.service.
See system logs and 'systemctl status cron.service' for details.
```

Nếu bạn vừa thay đổi nội dung file unit hay thêm file mới và muốn systemd nhận thay đổi đó, cần chạy câu lệnh "daemon-reload" để điều khiển systemd đọc file unit mới

```
# systemctl daemon-reload
```

## Bật service khởi động cùng máy

Khái niệm này gọi là "enable" một unit. Và để bỏ khởi động cùng máy, dùng "disable". Hai câu lệnh này sẽ tự "daemon-reload" sau khi chạy.

Về mặt bản chất, systemd sẽ tạo/xóa các symlink cần thiết để nó biết chương trình nào cần khởi động cùng máy.

```
# systemctl disable cron
Synchronizing state of cron.service with SysV init with /lib/systemd/systemd-sysv-install...
Executing /lib/systemd/systemd-sysv-install disable cron
insserv: warning: current start runlevel(s) (empty) of script `cron' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (2 3 4 5) of script `cron' overrides LSB defaults (empty).

# systemctl enable cron
Synchronizing state of cron.service with SysV init with /lib/systemd/systemd-sysv-install...
Executing /lib/systemd/systemd-sysv-install enable cron
insserv: warning: current start runlevel(s) (empty) of script `cron' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (2 3 4 5) of script `cron' overrides LSB defaults (empty).

```



### Hiển thị unit file của 1 service


```
$ systemctl cat cron
# /lib/systemd/system/cron.service
[Unit]
Description=Regular background program processing daemon
Documentation=man:cron(8)

[Service]
EnvironmentFile=-/etc/default/cron
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS
IgnoreSIGPIPE=false
KillMode=process

[Install]
WantedBy=multi-user.target

# systemctl cat rsyslog
# /lib/systemd/system/rsyslog.service
[Unit]
Description=System Logging Service
Requires=syslog.socket
Documentation=man:rsyslogd(8)
Documentation=http://www.rsyslog.com/doc/

[Service]
Type=notify
ExecStart=/usr/sbin/rsyslogd -n
StandardOutput=null
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=syslog.service

```

## Cú pháp của một unit file


Câu lệnh để chạy chương trình nằm trong mục [Service], ExecStart.
Tham khảo file unit của các service khác sẽ đủ để tự viết 1 file unit.


## What's next?
Trên đây chỉ là những câu lệnh / kiến thức liên quan đến phần "service manager" của systemd, trong khi đây là một hệ thống nhiều thành phần phức tạp hơn nhiều.

Tham khảo thêm phần log bằng [journalctl](http://www.familug.org/search/label/journalctl), một thành phần trong systemd.


## Tham khảo

man 1 systemd
man 1 systemctl
man 5 systemd.unit

Bài viết thực hiện trên Ubuntu 16.04

Hết.
HVN at http://www.familug.org/ and http://pymi.vn
Đăng ký học lập trình #Python 3 từ con số 0 tại PyMI.vn - lớp Sài Gòn khai giảng đầu tháng 8, lớp Hà Nội khai giảng giữa tháng 9. Xem chi tiết tại https://pymi.vn/ #PyMI #PyFML