Linux配置和管理

文件管理

在Linux/UNIX中,所有的对象都被视为文件,包括普通文件、目录、设备、套接字。

目录路径

pwd                   # Print Working Directory
dirname filename      # parent directory
basename filename     # 

pwd列出正在工作的目录,用于显示你当前所处的目录名。pwd命令总是返回你当前所处的目录的完全路径名。dirname返回查询路径的父目录(从文件路径中截取)。basename仅返回文件的名称。

readlinkrealpath解析文件的绝对路径,跟踪解析所有符号链接。

readlink -e \ # 解析过程中的所有目标必须存在 => realpath -e filename
         -f \ # 除最终目标外所有目标必须存在 => realpath    filename
         -m \ # 允许目标不存在             => realpath -m filename
         FILENAME 
切换目录
cd  [dir_name]     # 切换工作目录(Change Directory)
chroot [OPTION] NEWROOT [COMMAND [ARG]...]  # 切换命令运行的根目录

不带任何参数时,将把你送回自己的用户主目录中(等效于cd ~)。..表示父目录。

登录完成后,工作目录为用户主目录。

创建目录

在每一个新的子目录中,均包含两个标准的项目:.代表当前目录和..代表父目录。

mkdir -m,--mode=MODE -p dir_name 
install [OPTIONS] -d dir1 dir2 ...   # 创建目录并设置权限

-m:可用来创建一个带有特定权限的子目录(chmod声明方式)。 -p:父目录不存在的情况下首先创建父目录,忽略已存在目录(默认报错)。

删除目录
rmdir -p dir_name ...   # -p 一次删除多个目录

dir_name不能为当前工作目录(即要在父目录中删除子目录)。应该拥有被删除目录的写该目录必须为空目录(即只包含...,否则使用rm -rf dir_name)。

显示目录中的项目

列表显示
ls [options] [dir_name]
文件过滤选项

-a:显示所有文件(包括以.开头的文件(夹)),-A仅忽略...-R:递归显示所有子目录的内容; -d:只显示目录条目的信息;

文件信息选项

-l:列表显示目录中文件的详细信息,与其他排序方式组合使用时则显示相应的排序字段;-g-l相似但不显示文件所有者,-o不显示用户组;

文件类型信息:- 表示普通文件(f);d 目录文件;b块设备文件例如磁盘;c字符设备文件,p命名管道(FIFO) ;l符号链接;s 套接字(socket);

--author:显示文件创建者; -n:显示数字形式的用户和用户组ID; -iinode序号将列在第一列; --time-STYLE:时间显示格式,包括:full-iso2020-03-07 15:07:15.542112573 +0800)、long-iso2020-03-07 17:34)、iso03-07 15:07)、localeMar 7 15:07)或+FORMAT--full-time:显示完整时间,等价于-l --time-style=full-iso-h:显示更加友好的文件长度信息(1K 234M 2G,等价--human-readable); -s:显示文件占用的磁盘容量; --block-size=SIZEK,M,G,T,P,E,Z,Y (powers of 1024)或 KB,MB,... (powers of 1000)

排序选项

--sort=WORDWORD=none(-U),size(-S),time(-t),version(-v),extension(-X),未声明排序选项时,默认按文件名排序。-c:按ctime(指文件的inode信息被改变的时间)排序;-u:按访问时间排序;-t:按修改时间排序,优先级低于-c-u-r:反向排序;

查看目录树
tree -L <n> path  # not built-in

-L <n>:搜索深度;-l:跟踪符号链接;

文件信息

获取文件的信息:

stat <path/to/file> -c,--format,--printf=FORMAT \
     -f,--file-system   # 显示文件所在文件系统信息而非文件信息

格式参数FORMAT可包含多个格式声明以及普通字符,--printf还可使用"\"转义字符;

格式内容格式内容格式内容格式内容格式内容
%n文件名%F文件类型%ggroup id%y修改时间%a八进制访问权限
%N"文件名"%sfile bytes%Ggroup name%Y修改时间戳%A字母访问权限
%h硬链接数%m挂载点%uowner id%w创建时间%x访问时间
%iinode数%CSELinux%Uowner name%W创建时间戳%X访问时间戳

stat外,还可以使用date获取文件修改时间

date -r <filename> [+"%Y%m%d"] 

获取文件类型:

file <path/to/file> \
    -i,--mime      \  # => --mime-type + --mime encoding
    -z,--uncompress \  # 尝试解压压缩文件并查看其中内容
修改文件属性

touch可以用于修改文件访问时间

touch filename
touch -d "2 hours ago" filename

普通文件

移动

如果源文件/目录与目标文件/目录同名,则用源文件/目录替换同名目标文件/目录的内容;否则,将源文件/目录移动到目标目录中;此时,目标目录必须存在,不会首先创建目录。

mv [-f]  file_path /path/newname

如果源与目标所在路径相同,mv等效于重命名。

批量重命名

将文件名中已知的部分内容替换为新的内容,其余部分(使用通配符表示)不变。

rename 's/pattern/replace/' FILES    # sed style
rename pattern replace FILES

pattern为Perl正则表达式,文件名FILES支持通配符(?*.txt)。

使用需注意,原始的rename不会检查已有文件而直接覆盖。

复制

cp [-raf] file_path /path/filecopy  # -a 保留原属性

cp的文件创建行为与mv相同。

安装

install支持设置目标文件的权限和属性(==不支持文件夹(递归)复制==):

  • -m,--mode=MODE:设置访问权限;

  • -g,--group=GROUP-o,--owner=OWNER:设置所属关系(chgrp,chown),代替当前进程的默认值;

  • -p, --preserve-timestamps:保留文件的访问/修改时间;

install [OPTION] -D [-T] SOURCE DEST   # single-file to file

-D:(递归)创建目标文件的父目录(mkdir -p),未指定该选项则不会自动创建目录;

install [OPTION] SOURCE... DIRECTORY   # single to dir
install [OPTION] -t DIRECTORY SOURCE...# multiple to dir (--target-directory)

-b,--suffix=BACKUP:备份选项以及备份目标文件夹;

删除文件

rm [-rf] file  # can use wildcard

使用-rf递归删除非空文件夹。

文件链接

硬链接hard link):是对原文件的引用(引用同一个inode,在inode中计数),与原文件等价(即拥有相同访问权限)。删除硬链接将减小inode计数,到inode计数为0时删除文件。

符号链接symbolic/soft link):保存到目标文件(夹)的路径(或相对路径),访问符号链接将跳转到目标文件(夹)。符号链接是一个独立的文件(具有相应的inode节点),因此具有独立的文件权限。删除原文件后,符号链接失效。

创建链接
ln -s /file/path /symbol/path	  # symbolic link
ln /file/path /symbol/path      # hard link file
ln -d /dir/path /symbol/path    # hard link 目录(不一定支持)
# -f,--force 移除已有文件链接 

符号链接的目标可以是任意内容(创建的时候不做检查合法性),符号链接支持跨文件系统。硬链接的目标必须存在且仅支持在同一设备的同一文件系统。

访问链接

==文件链接解引用时,相对路径的父目录为文件链接所在目录==,解析符号链接目标时是递归式解析。

工作目录路径:如果切换工作目录到符号链接指向的目录,则工作目录路径为符号链接的路径而非目标目录的真实路径(比较pwdrealpath的输出结果),向上跳转(..)会返回符号链接所在目录。

在Linux中创建的符号链接在Windows中仍然能访问(WSL),但Windows不做递归解析,仅以当前工作目录路径为参考解析符号链接,因此使用相对路径的多级符号链接解析会出错

临时文件

在指定目录下(默认为/tmp)创建临时文件并输出文件路径。

tempfile --directory PATH # [Debian] 
mktemp -p PATH     # [Fedora-coreutils]
       --directory # 创建目录而非文件

查找文件

which <command>
command -V <command>

从系统环境变量中查找文件并返回绝对路径。

查找目录中的文件

find [-HLP][-D debugopts][-Olevel][start_dir...][expression]

start_dir表示查找路径,可以使用绝对路径,也可以使用相对路径,可以同时指定多个目录;如果没有指定,则默认为当前目录。==默认输出信息为查找到的文件夹和文件信息,并包含从查找目录开始的完整路径信息。==

选项(Option)

选项控制find访问文件系统的行为

-H-L-P(默认)控制处理符号链接的行为。

-P表示不解析任何符号链接; -H表示除了命令行提供的文件名外,不解析其他符号链接。如果符号链接不能被解析,则返回符号连接本身的信息; -L表示在可能的情况下解析符号链接,反之返回符号链接自身的信息。(-follow deprecated)

-D debugopts:输出诊断信息。

-Olevel:查询优化。默认首先执行基于文件名的表达式(-name-regex等);其次执行-type-xtype的表达式(通过readdir()读取文件类型)。

读取上述选项之后,检查后续参数是否为文件/路径,直到以-(!开始的参数(也可以使用--声明选项参数的结束)。剩余参数为控制搜索行为的表达式。

表达式(Expression)

表达式用于控制如何匹配文件以及对匹配文件的操作。表达式可以包含以下内容:

  • Tests:测试文件属性,返回true|false
  • Actions:对匹配结果执行操作,根据操作结果返回true|false;如果表达式没有包含操作,则默认为-print
  • Global options:全局选项,总是返回true
  • Positional options:仅影响其后的测试或操作,总是返回true
  • Operator:将表达式中多个内容连接起来:-o(逻辑OR)、-a(逻辑AND);表达式内容之间默认使用-a连接;可以使用()声明优先级。
全局选项
  • -d,-depth:先处理文件夹中的内容,再处理文件夹本身;
  • -maxdepth,-mindepth LEVEL:指定搜索的层级,0表示起始点本身;
  • -mount, -xdev:不搜索挂载的其他文件系统目录;
  • -help,--help,--version:帮助、版本信息。
位置选项
  • -daystart:计算时间时从今天开始,而非24小时前算起。影响其后的测试条件-amin, -cmin, -mmin, -atime, -ctime-mtime

  • -regextype TYPE:默认为emacs,包括:awk,egrep,grep,sed等。

    -regextype egrep在CentOS 7 上不支持{}

测试条件
表达式说明
-name PATTERN查找==文件名==匹配PATTERN的文件,可以使用通配符*,?,[]
-path PATTERN==从搜索路径开始的完整文件名(非绝对路径)==与PATTERN进行匹配
-wholename)。
-regex PATTERN使用正则表达式匹配文件。文件名以./开头的==完整相对路径==,
注意在正则表达式前添加.*以匹配前缀;
-atime [+-]N
-ctime [+-]N
-mtime [+-]N
判断最近访问(-a),状态变化(-c),修改(-m)时间:
如果参数为N,表示时间在N天之内
(0表示0~24小时,1表示24~48小时,…)
-amin [+-]N时间单位为min(类似地-cmin-mmin
-anewer FILE测试最近访问时间是否比FILE更近(-cnewer,-newer)。
-used [+-]N在文件状态改变N天(+N,-N)之内文件被访问过。
-empty测试文件或文件夹是否为空。
-size n[u]文件大小:单位u=cwbkMG:
-fstype TYPE测试文件所在的文件系统的类型是否为TYPE
-uid [+-]N文件的用户ID(组ID-gid)是否为N(或+N,-N)。
-user NAME文件的用户名(组名-group)是否为NAME(允许使用ID)。
-nouser文件的用户ID(组ID-nogroup)没有对应的用户(组)。
-lname PATTERN符号链接所指向的文件的文件名是否与PATTERN匹配。
-perm pmode文件的权限是否与pmode匹配,
pmode可以是符号或数字模式,例如:-perm 664
直接指定单项权限-readable-writable-executable
-type <c>文件类型bcdpfls
-xtype c除符号链接以外,与-type作用一致;
-inum [+-]Nrarely useful.
-samefile NAME文件与NAME为同一个文件。
-links [+-]NFile has n hard links.

匹配文件名的测试命令前添加i(例如-iname)为忽略大小写版本。 通配符需要使用引号包围以防被shell展开。 参数如果为+N,则表示大于N,如果为-N则表示小于N

运算符
运算符表达式
()(EXPR)
! -not!EXPR –not EXPR
-a -andEXPR1 –a EXPR2 EXPR1 –and EXPR2
-o -orEXPR1 –o EXPR2 EXPR1 –or EXPR2
,EXPR1, EXPR2
动作
命令说明
-print, -print0print0会在文件名结尾追加“null”。
-fprint FILE
-fprint0 FILE
打印完整文件名到FILE
如果文件不存在则创建文件;
如果存在,则文件内容被删除;
即使没有输出内容,该文件仍然会被创建。
-ls
-fls FILE
ls -dils格式打印到标准输出。-fls输出到文件。
-printf FORMAT
-fprintf FILE FORMAT
位宽和精度说明类似于C语言的printf(man find)。
-execdir command
-exec command
-execdir将其后直到;的所有内容视为command
同时将其中的“{}”替换为查找结果的文件名。
command中的特殊字符需要使用“\”或“'”以防被shell展开。
-execdir command {}+
-exec command {}+
命令末尾的“{}”展开为匹配文件名称的列表;
-okdir command
-ok command
询问用户是否执行命令
-delete删除成功返回真;如果失败,生成错误信息;
查找文件示例

高亮find查找结果:

find ./ -name '*.tar.gz' | grep --color '.tar.gz'

打印查找到文件的详细信息。

find ./ -name '*.tar.gz' -exec ls -lh {} ';' 

删除文件:

find . -maxdepth 1 -newer archive.tar.gz -execdir rm -rf {} ';'

在过滤文件中查找内容:

find ./ –name '*.cpp' –exec grep -Hn 'main' {} ';'
find ./ -name "*.log" | xargs grep –Hn 'ERROR'

grepfind同时使用时,默认不会输出文件名(添加-H选项),也不会高亮文本(使用--color选项)。

查找文件内容

使用grep查找具有给定内容和文件名的文件:

grep -rl 'main' --include='*.cpp' ./  # 输出匹配文件的文件名
grep -rn 'main' --include='*.cpp' ./  # 输出匹配行的行号和内容

硬件管理

查看硬件信息

sudo dmidecode -t,--type type_code|type_keyword
sudo dmidecode [options] | grep -A16 'System Information$'   # 系统和主板信息

硬件类型(type_keyword)包括:bios, system, baseboard, chassis, processor, memory, cache, connector, slot。每种类型可能包括多个子类型(type_code)。

sudo lshw \               # list hardware [yum install lshw]
     -class <hw_class> \  # class can be found using lshw -short
     -{html|xml|json}  \  # 输出格式
     -short \ # device tree: 优先级高于输出格式
     -businfo # showing bus information

硬件类型可通过lshw -short的输出获取,包括:systembusmemoryprocessorstorageinputdisplaydiskvolumenetworkpower等。

其他工具:hwinfo(默认未安装到系统);hardinfo(图形界面)。

CPU
lscpu              # CPU信息概述
nproc              # number of process unit
sudo lshw -C processor
cat /proc/cpuinfo  # CPU details
sudo dmidecode --type processor # details

cpuid获取详细信息(未安装)。

cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
# 8  Intel(R) Xeon(R) CPU            E5410   @ 2.33GHz
## (CPU with 8 logical core)
cat /proc/cpuinfo | grep 'physical id' | uniq -c
#      4 physical id      : 0
#      4 physical id      : 1
### (2 physical CPU with 4-core)
内存
free -h	-w	# summary
cat /proc/meminfo  # details
vmstat -s
sudo dmidecode -t memory   # Memory Device

all tmpfs pages will be shown as “Shmem” in /proc/meminfo and “Shared” in free(1).

磁盘信息

列出存储设备信息:

sudo fdisk -l [device_name]  # 查看磁盘设备 => sudo parted /dev/sda print
lsblk    # 列出块设备
sudo blkid /dev/sda
# /dev/sda: UUID="3255683f-53a2-4fdf-91cf-b4c1041e2a62" TYPE="ext4"

查看序列号:

udevadm info --query=all --name=/dev/sda | grep ID_SERIAL
hdparm -I /dev/sda   # install hdparm
lshw -class disk     # install lshw
smartctl -i /dev/sda # install smartmontools

位于磁盘阵列中的磁盘序列号不可见(系统读取的是RAID分配的ID)。

文件系统信息

列出系统支持的文件系统:

cat /proc/filesystems

exfat格式支持需要安装exfat-fuseexfat-utils包;NTFS格式需要安装ntfs-3g包(CentOS)。

列出挂载的(文件或目录所在)文件系统信息。

df [-ahHkT] [目录或文件名]
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sdd        251G  1.6G  237G   1% /
# tmpfs            13G  252M   13G   2% /mnt/wsl

-hH:以合适的单位显示数据(1024进制,-H为1000进制),提高可读性; -i,--inodes:显示inode信息而非磁盘容量信息; -T,--print-type:==打印文件系统类型==,例如ext4tmpfs等; -t,--type=TYPE:仅显示指定类型文件系统;-x,--exclude-type=TYPE排除指定类型;

列出文件或目录的磁盘占用量disk usage):

du [-ahskm] 文件或目录名称

-c, --total-h, --human-readable-s, --summarize-d,--max-depth=N:显示最大路径深度;

磁盘管理

磁盘分区与格式化

注意:以下操作可能导致数据丢失,应事先做好数据备份!!!

使用fdiskparted操作文件分区表(fdisk -l查看磁盘信息):

sudo fdisk device_name   # 操作分区表
# fdisk命令
# [F] 列出未分区的空闲空间    n 新增分区
# l   列出已知分区类型        t 更改分区类型
# p   打印分区表             d 删除分区  
# [i] 打印选择的分区信息      v 验证分区表
# m   打印命令列表           g 创建GPT分区表
#                          o 创建DOS(MBR)分区表
# q   放弃更改并退出         w 保存分区更改

未添加device_name时,列出系统内所有存储设备(/dev)的分区(partition)信息。

GParted -- Live CD/USB/PXE/HDWith GParted you can resize, copy, and move partitions without data loss. gparted是一款图形界面的分区工具。

更改正在使用的分区:首先删除分区(记录下分区表的起止位置),然后重新创建分区,并指定新的起止位置(注意不要和已有分区重叠)和分区类型,保存并退出(使用工具cloud-utils.growpart)。分区表更改不会立即生效,因此可以修改正在使用的分区,重启机器或使用partprobe [/dev/sda]kpartx [/dev/sda]命令重新载入新的分区表。如果是普通卷,则需要使用resize2fs更新文件系统容量,如果是LVM物理卷,则使用pvresize更新(resize2fs无法操作LVM物理卷)。

磁盘格式化

新建分区后,需要对分区进行格式化设置文件系统才能进行挂载使用。整个磁盘也可以不进行分区直接格式化。

mkfs -t <fstype> /dev/sda
mkfs.<fstype> options /dev/sda  # 格式化分区/dev/sda1

fstype文件系统类型,例如 ext4, xfs, btrfs , ZFS等(系统有支持才会生效)。在选择文件系统类型时,如无特殊要求,选择系统中已有分区类型(默认类型),确保兼容和稳定性。

mke2fs:创建ext2/ext3/ext4文件系统,对应命令:mkfs.ext2|3|4ext文件系统的i-node节点总数在文件系统创建后不能改变,调整文件系统容量将按比例调整inode数量(bytes-per-inode)。

Linux File System Types Explained, Which One Should You Use (linuxiac.com)

数据恢复

TestDisk Step By Step - CGSecurity

How to recover partitions and data using Linux - Tutorial (dedoimedo.com)

How to recover lost partition using Linux (simplified.guide)

TestDisk is powerful free data recovery software! It was primarily designed to help recover lost partitions and/or make non-booting disks bootable again when these symptoms are caused by faulty software: certain types of viruses or human error (such as accidentally deleting a Partition Table).

==Even though the old partition table was destroyed, it was just a pointer to the start and end addresses of the actual data, so to speak.==

The new and definite CloneZilla tutorial (dedoimedo.com)

磁盘检验

fsck [-t <fstype>] [-ACay] /dev/sda

用来检查和维护不一致的文件系统。若系统掉电或磁盘发生问题,可利用fsck命令对文件系统进行检查。

磁盘挂载与卸除

mount -t <fstype> -L <label> -o <opts> -n /dev/dev_name /mnt/mnt_name
mount --move /mnt/userdirs /home    # move mount point of a filesystem
umount [-fn] [/dev/dev_name | /mnt/mnt_name]
findmnt --types <fstype>            # 查看已挂载的文件系统

如果挂载的目标路径下有数据,则数据会被隐藏;卸载磁盘后可恢复访问原有数据1

Sharing a mount on multiple mount points

挂载NTFS文件系统:

yum install fuse ntfs-3g   # centos
mount -t ntfs-3g /dev/sdb1 /mnt/win

如果卸除设备时出现设备忙的错误,可查看正在使用该设备的进程有哪些并尝试关闭进程。

挂载CD
mount -t auto [-r] /dev/cdrom /mnt/cdrom # 挂载CD
挂载可移动介质

挂载磁盘的目标文件夹必须存在,挂载的磁盘应该已经使用支持的文件系统格式化。可移动磁盘设备标识类似于内置磁盘(使用fdisk -lparted -l查看)。

自动挂载
  1. 将挂载命令写入开机启动脚本;

  2. 配置systemd.mount单元文件

    [Mount]
    What=/dev/sda
    Where=/data
    Type=ext4
    Options=
    
  3. 使用/etc/fstab配置,systemd会将其中的内容转换为单元文件;

    # DevicePath    MountPoint  FS Type      Mount Options       Dump  CheckOrder
    /dev/sdba         /data      ext4             -               0        1
    LABEL=t-home2     /home      ext4    defaults,auto_da_alloc   0        2
    SERVER:PATH
    

逻辑卷管理LVM

Logical Volume Management, gives users the power to pool and abstract the physical layout of component storage devices, to gather existing storage devices into groups and allocate logical units from the combined space as needed.

LVM存储信息

显示系统中的LVM兼容卷,包括可转换为LVM物理卷(Physical Volumns)的存储设备:

sudo lvmdiskscan \
     -l # 仅显示LVM物理卷, ==> pvscan, pvs, pvdisplay

显示系统中的物理卷组(Virtual Group)信息:

sudo vgscan  # => vgs, vgdisplay

显示系统中的逻辑卷(Logical Volumn):(逻辑卷设备路径、VG NamePV

sudo lvscan # lvs, lvdisplay [-m]
管理LVM存储

从原始磁盘创建LVM物理卷,注意将磁盘上原有数据备份,加入LVM管理后将覆盖原有数据。

A header is written to storage devices to mark them as free to use as LVM components.

sudo pvcreate /dev/sda /dev/sdb ...
pvresize /dev/sda1
pvresize --setphysicalvolumesize 40G /dev/sda1 # shrink

如果物理磁盘分区通过fdisk进行了扩展,可以通过pvresize更新LVM物理卷的容量。也可以将空余磁盘空间创建为一个新的物理分区,设置为LVM PV并加入LVM虚拟卷组。

将物理卷创建为卷组,通常只需要一个卷组并在此之上创建虚拟卷。

sudo vgcreate volume_group_name /dev/sda /dev/sdb ...

向卷组中增加物理卷:

sudo vgextend volume_group_name /dev/sdb

创建虚拟卷,创建后需要对虚拟卷进行格式化

sudo lvcreate -L 10G -n VolumnName LVMVolGroup   # 绝对容量
sudo lvcreate -l 100%FREE -n VolumnName2 LVMVolGroup # 相对容量

虚拟卷的底层物理磁盘分配方案支持线性(linear,默认)、striped(RAID 0)、raid1等。

虚拟卷容量调整,使用-L选项增加/减少绝对容量,或用-l选项增加相对容量。

sudo lvresize -L +5G --resizefs LVMVolGroup/vol_name
sudo lvresize -l +100%FREE --resizefs LVMVolGroup/vol_name

XFS filesystem shrinking is unsupported. resize2fs is for ext filesystems.

RAID

Hardware RAID

在BIOS中配置磁盘的RAID选项,参考产品用户手册。

Software RAID
  1. How To Use LVM To Manage Storage Devices on Ubuntu 18.04.
  2. How To Create RAID Arrays with mdadm on Ubuntu 18.04 | DigitalOcean.

显示设备

查看显示设备:

lspci | grep -i vga            # <== install pciutils
sudo lshow [-short] -c CLASS   # list hardware, CLASS for class/description
sudo lspci -v -s 03:00.0
安装Nvidia显卡驱动
rl=$(uname -r)
yum install gcc gcc-c++ make kernel-devel-$rl kernel-headers-$rl
apt install gcc make linux-headers-$rl [libglvnd]

注意内核开发包的版本需要于系统内核版本完全一致,否则无法成功安装驱动程序。

检查nouveau模块是否加载,已加载则先禁用

lsmod | grep nouveau
# edit: /usr/lib/modprobe.d/blacklist-nouveau.conf  # [Ubuntu]/etc/modprobe.d/*
blacklist nouveau
options nouveau modeset=0
dracut -force   # 重启系统,使内核模块配置生效 [Ubuntu]update-initramfs -u

安装驱动程序:

./NVIDIA-Linux-x86_64-390.46.run --no-opengl-files --ui=none --no-questions --accept-license
# edit: /etc/rc.d/rc.local
nvidia-smi -pm 1   # GPU驱动模式设置为常驻内存
nvidia-smi         # nvidia proprietary driver => watch -n 1 nvidia-smi
Ubuntu桌面版显卡驱动
ubuntu-drivers devices             # 列出可用驱动
sudo ubuntu-drivers autoinstall    # 安装推荐驱动
sudo apt install nvidia-driver-440 # 安装指定名称驱动

安装完成后重启。

How to install the NVIDIA drivers on Ubuntu 20.04 Focal Fossa Linux - Linux Tutorials - Learn Linux Configuration

网络设备配置管理

系统配置

系统信息

操作系统

uname [options]
选项说明
-a, --all包括以下系统信息:
-s, --kernel-name内核名称(Linux
-n, --nodename网络主机名称(使用hostnamectl设置)
-r, --kernel-release内核发行版本(3.10.0-1160.24.1.el7.x86_64
-v, --kernel-version内核版本(#1 SMP Thu Apr 8 19:51:47 UTC 2021
-m, --machine机器的硬件架构名称(x86_64
-o, --operating-system操作系统(GNU/Linux

-i,--hardware-platform-p, --processor(不可移植),通常与-m输出一致。

系统版本信息
cat /etc/issue          # [Ubuntu]
cat /etc/lsb-release    # [Ubuntu]
cat /etc/os-release     # [Ubuntu|CentOS]
lsb_release -crid       # 包含版本号详细信息,CentOS需要安装redhat-lsb-core 
rpm -qa centos-release  # [Fedora/CentOS]
rpm -qi basesystem      # [Fedora/CentOS](包含安装日期)
操作系统安装时间

通过文件系统创建时间判断操作系统安装时间:

tune2fs -l $(df / | awk '$6 ~ /\// {print $1}') | grep 'Filesystem created:'  # -> dumpe2fs
rpm -qi setup|setuptool|basesystem    # [Fedora/CentOS]

tune2fs是设置ext2/ext3/ext4文件系统参数的工具。

主机名

hostnamectl  # 显示主机信息(主机名、系统名、架构...)
hostnamectl set-hostname 'gfs.server.03.net' # 设置主机名
sysctl -n kernel.hostname

某些服务(例如Cloudera)需要检测主机名与域名(FQDN)的一致性,为了避免产生警告,将主机名设置为域名。

WSL-Ubuntu中hostnamectl不可用。

域名映射

sudo vi /etc/hosts
# change <hosts> file
192.168.137.11 new-host-name

可能需要重启。

日期时间

显示时间

date                           # Sun May 16 13:07:15 CST 2021
date +'%H'                     # %T %c %F
date -d,--date='7:00:00' +'%s' # parse a date and display it
date --date='@2147483647'      # parse a timestamp (seconds)
date -r,--reference=FILE       # 显示文件最近修改时间

默认显示当前时间,使用-d,--date指定要显示的时间的字符串;字符串缺少的部分设为当前时间。空字符串表示当天开始时间。

A list of date command field descriptors

获取日期字段
格式声明含义格式声明含义格式声明含义
%YYYYY%mmm%ddd
%HHH(00-23)%MMM(00-59)%SSS
%s时间戳(秒)%3N毫秒%N纳秒
%f微秒
格式化日期字段

%后可额外设置表示填充的字符:-不填充;_填充空格;0填充0(默认);^使用大写字母;#(尽可能)改变字符大小写。

格式含义格式含义格式含义
%clocale's datetime%xlocale' date%Xlocale's time
%D%m/%d/%y%F%Y-%m-%d
%T%H:%M:%S%r12:11:04 PM%X23:13:48(locale)
%yyy%e%_d
%Ihh(01-12)%k_H(0-23)%l_h
%jddd: day of year%wday of week(0-6)
0 is Sunday
%uday of week(1-7)
1 is Monday
%Wweek of year(00-53),
Monday first
%Uweek of year(00-53),
Sunday first
%Vweek of year(01-53),
Monday first
%pAM/PM%Pam/pm%qquater 00-04
%z时区-0400%:z-04:00%::z-04:00:00
%Z时区类型EDT/CST

设置时间:

timedatectl [status]		# 显示系统的日期、时间和时区等信息
timedatectl set-time "2012-10-30 18:17:16"  # <== timedatectl set-ntp no
date -u,--utc=MMDDhhmmCCYY.ss  # print or set datetime
date -s,--set=STRING
timedatectl set-timezone <Asia/Shanghai>
timedatectl list-timezones	# 列出已知时区

系统启动时间:

uptime

系统引导配置

引导配置文件:

/etc/default/grub
/etc/grub/grub.cfg # auto-generated by grub-update

选择默认用户界面:

sudo systemctl set-default multiuser.target # terminal shell
sudo systemctl set-default graphical.target # GUI

添加开机启动项

  1. 编辑/etc/rc.local脚本(兼容性目的),并设定可执行权限(sudo chmod 755

    适合较短的命令

  2. 将启动项的脚本添加到/etc/init.d目录下,并设置可执行权限

    ln -s task.sh /etc/init.d/task
    sudo chmod +x /etc/init.d/task
    
    cd /etc/init.d
    sudo update-rc.d task defaults 95  # execute order
    sudo update-rc.d -f task remove  # remove the task
    

    如果使用需要开机通过chkconfig设置开机启动的服务,则脚本开头应该包含以下信息:

    #!/bin/bash
    # chkconfig: 2345 20 80
    # description: Saves and restores system entropy pool \
    # for higher quality random number generation.
    

    chkconfig: 2345 20 80表示这个服务在运行级别2345下运行,20表示开机启动优先权重,80表示关闭优先权重。

    也可以手动调用chkconfig添加开机启动服务

    chkconfig --add my-service
    

    实际上chkconfig --add命令是将/etc/init.d中的启动脚本软连接到/etc/rc.d/rcx.drc0.d ... rc6.d)0-6个运行级别对应相应的目录,都是位于/etc/init.d中脚本的软连接。

    /etc/init.d/中的脚本,可以通过命令:

    service service_name [start/stop]
    

    启动或者关闭(添加到启动脚本中实现自启动,见方法1或)。

  3. 将启动任务的脚本放到目录/etc/profile.d下,系统启动后将自动执行其中的shell脚本。

  4. 注册为systemd托管的服务,在系统启动时运行。

内核配置

内核配置项对应文件系统中/proc/sys目录。

读取内核配置项:配置项具有分级结构(对应上述目录树),名称以./分隔。

sysctl -n variable          # 输出value, 默认输出 variable = value
sysctl -a -pattern PATTERN  # 打印所有配置项(某些配置项需要管理员权限才可访问)

-n,--values:仅打印配置项的值;-N,--names:仅打印配置项的名称;

sysctl -q,--quiet \        # 不将设置的值回显到屏幕
       -w variable=value ...

加载内核配置:

sysctl -p,--load [FILE] # 默认加载/etc/sysctl.conf
sysctl --system         # 加载系统中所有配置文件

文件系统

最大打开文件数量限制
ulimit -n 8192  # 默认1024, 临时修改

编辑/etc/security/limits.conf,永久修改:

# domain type item   value
    *    soft nofile 16384  # soft limits of Number of Open file
    *    hard nofile 16384  # hard limits 

linux - Fix with ulimit -n 8192 - Stack Overflow

inotify文件监控数量限制

文件监控数量限制如果设置太小,容易触发inotify watch limit reached错误。临时设置运行时参数:

sudo sysctl fs.inotify.max_user_watches=524288  # 8192 default

永久修改配置(/etc/sysctl.conf)并运行sysctl -p重新加载。

fs.inotify.max_user_watches=524288

字体

用户可将字体安装在/usr/share/fonts目录下,使用fc-list(需要安装fontconfig)可查看系统中可用字体。

fc-list                                    # "FONT_PATH: FONT_FAMILY:style=STYLE"
fc-list : family                           # 仅输出字体名
fc-list :lang=zh family style file spacing # "PATH: FAMILY:style=STYLE:spacing=SPACE"

日志

大部分的发行版都内置使用syslog系统日志,常见的日志一般存放在 /var/log 中。

常见的系统日志
日志名称记录信息
alternatives.log系统的一些更新替代信息记录
apport.log应用程序崩溃信息记录
apt/history.log使用apt安装卸载软件的信息记录
apt/term.log使用apt时的具体操作,如package的下载、打开等
auth.log登录认证的信息记录
boot.log系统启动时的程序服务的日志信息
Consolekit/history控制台的信息记录
dist-upgradedist-upgrade 这种更新方式的信息记录
dmesg启动时,显示屏幕上内核缓冲信息,与硬件有关的信息
dpkg.logdpkg 命令管理包的日志
faillog用户登录失败详细信息记录
fontconfig.log与字体配置有关的信息记录
kern.log内核产生的信息记录,在自己修改内核时有很大帮助
lastlog用户的最近一次信息记录。
wtmp登录信息的记录。
btmp远程登录信息记录。
syslog系统信息记录

日志一般都是文本文件,可使用 lesscatmore 等工具查看。 wtmplastlog 是二进制文件,需要使用lastlastlog工具来提取其中的信息。

rsyslog

systemd-journal

查看日志

筛选日志:

journalctl --system|user          # 查看系统/当前用户日志
journalctl -u,--unit=UNIT
           -t,--identifier=STRING # 查看指定syslog标识的日志
           -S,--since=DATE        # '2022-05-01 [12:00:00]'
           -U,--until=DATE

追踪日志更新:

journalctl -f,--follow
           -n,--lines=NUM         # 显示日志数量
日志存储设置
journalctl --disk-usage
journalctl --rotate
journalctl --vacuum-time=2d   # 清理超过2天的日志
journalctl --vacuum-size=100M # 清理超过100M的日志
journalctl --vacuum-files=5   # 清理超过数量的日志
systemctl kill --kill-who=main --signal=SIGUSR2 systemd-journald.service
rm -rf /run/log/journal/* 
rm -rf /var/log/journal/* 
systemctl restart systemd-journald.service
journalctl --verify

终端命令记录

histroy   # 显示历史记录: cat ~/.bash_history
history -c  # 删除历史记录:rm ~/.bash_history

用户登录信息

who /var/log/wtmp  	# 查看用户登录历史记录
last [username] [-f /var/log/btmp] # 默认读取/var/log/wtmp
lastlog [-u username] [-t 5] [-b 60]

浏览器(桌面环境)

ls -l ~/.opera/cach4
ls -l ~/.mozilla/firefox/*.default/cache

日志清理

logrotate是Linux自带的文本日志处理工具,可进行切割、打包、压缩等处理。其配置文件位于/etc/logrotate.conf以及/etc/logrotate.d/

/tmp/dask/*log {
  rotate 7       # 指定日志文件删除之前转储的次数,0直接删除,-1不删除
  daily          # 指定转储周期:hourly,daily,weekly,monthly, yearly
  minsize 1M     # 文件大于1M时才会进行轮转
  maxsize 100M   # 文件大于100M时强制进行轮转(即使还未到轮换周期)
  size    100M   # 指定轮转大小: k/M/G (与轮转周期互斥)
  minage  10     # 文件创建超过10天才进行轮转
  maxage  100    # 移除创建超过100天的已轮转的文件
  missingok      # 忽略不存在的日志文件/nomissingok
  ifempty        # 即使日志文件为空文件也做轮转/noifempty
  dateext        # 使用当期日期作为命名格式,默认值取决于轮换周期
  dateformat -%Y%m%d%H # 
  nocompress     # 
  create [[mode] owner group] # 新日志文件的权限, 默认和原来的文件相同的权限
  copytruncate   # 复制并清空日志文件(override create)*
  prerotate
  	script	
  endscript
  postrotate     # postrotate脚本 
    /sbin/nginx -s reload  
  endscript  # postrotate脚本结束
}

*:适用于日志输出程序无法获取日志文件打开状态的情况;但可能造成少量日志丢失。

logrotate通过ctrontab调度,默认每天运行一次(除非任务指定更小的周期)。可手动立即执行:

logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf

软件管理

各发行版提供的软件仓库与软件管理方案。本章介绍,当前主要的跨发行版软件管理解决方案。

Snap

Snap将软件及其依赖打包到独立环境,它的运行环境是容器化的沙箱,从而避免各发行版兼容性问题并保证一定的安全性。

image-20210731135944209

安装snap

Ubuntu/Debian系统预装snapd,使用snap version查看。

sudo yum install snapd  # [epel-release]
sudo systemctl enable snapd # 安装后需要手动启动

snapd无需持续在后台运行,仅在执行snap命令时被调用运行。

安装和升级snap软件

snap find "media player"
sudo snapd install 'appname'
sudo snap refresh 'appname'    # update
snap list  # 列出已安装的软件的简要信息
snap info 'pkgname'| 'pkgname.snap'  # 查看[已安装]软件包信息
          --color=auto|always|never
          --verbose

安装classic类型的软件,此类软件不受沙盒限制:

sudo ln -s /var/lib/snapd/snap /snap
sudo snap install julia --classic

下载snap包和离线安装:

snap donwload 'package name'
              --target-directory=.
              --channel=5.x/stable
snap ack path/to/package_name.assert  
snap install path/to/package_name.snap
             --dangerous  # 如果没有执行ack,则需要该选项才可以安装
snap安装目录
/snap               # -> Debian based
#/snap/bin                   - Symlinks to snap applications.
#/snap/<snapname>/<revision> - Mountpoint for snap content.
#/snap/<snapname>/current    - Symlink to current revision, if enabled.
/var/lib/snapd/snap # -> RHEL based
snapying用的配置文件/数据目录
/var/snap/"snap_name"
移除snap软件
snap remove "snap_name"  
     --purge  # 不保存软件的数据

软件的所有数据将自动备份(automatic snapshopt)以便后续恢复。

备份和恢复

snap save 'appname' --users "all"  # 创建用户、系统和配置数据的快照。
snap saved --id ID
snap forget "id" "appname"
snap restore "id" "snap_name" --users "all"  # 使用指定快照恢复其中的用户、系统和配置数据。
snap export-snapshot "id" /path/to/export
snap import-snapshot /path/to/import

不同版本(epoch)之间不能恢复数据。

回退到上个版本并恢复数据(不包括共享数据):

sudo snap revert 'appname' --revision ID 

snap配置

snap get "appname"
snap set "appname" key1=value1 key2.subkey=value2
snap unset "appname" key1 key2

管理snap应用的运行状态

查看服务运行状态和日志:

snap services <appaname>  # 查看APP提供的服务的运行状态
# => systemctl status snap.<appname>.<appserivce>
snap logs -f <appname>.<servicename> 
启动应用软件

如果安装未生成启动软件的快捷方式,可通过命令启动。

snap run <appcommand>   # 命令可通过snap info查看
管理软件服务

可使用snapsystemctl来控制服务运行。snap服务默认会在失效后自动重启。

sudo snap start/restart/stop <appname>
sudo snap restart <appname>.<servicename>
sudo systemctl restart snap.<appname>.<servicename>

AppImage

AppImage比较简单易用,不需要安装额外的工具,整个软件都在一个文件里,下载后可以直接运行。里面有个SquashFS的文件系统,运行的时候会挂在到一个临时的地方,里面有所有只读的文件,包括可执行文件、库文件、静态数据等。除此之外都和普通的软件运行环境是一样的。

Similar projects · AppImage/AppImageKit Wiki (github.com)

Flatpak

linuxbrew

安装发行版软件仓库缺失的软件。

安装linuxbrew

SRC_URL='https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh'
/bin/bash -c "$(curl -fsSL $SRC_URL)"

官方安装脚本下载以及官方源(github)的速度都比较慢,推荐使用代理进行安装。或者使用国内镜像进行安装和后续软件安装,配置镜像源相关环境变量:

MIRROR="https://mirrors.tuna.tsinghua.edu.cn"
export HOMEBREW_BREW_GIT_REMOTE="$MIRROR/git/homebrew/brew.git"
export HOMEBREW_CORE_GIT_REMOTE="$MIRROR/git/homebrew/homebrew-core.git"
export HOMEBREW_BOTTLE_DOMAIN="$MIRROR/homebrew-bottles"

执行以下命令下载安装脚本并执行安装:

git clone --depth=1 $MIRROR/git/homebrew/install.git brew-install
bash brew-install/install.sh
rm -rf brew-install

安装完成后根据输出提示,将初始化命令加入shell配置文件。然后,根据输出信息,安装建议的编译环境,用于brew进行本地编译打包。

brew的默认安装位置为/home/linuxbrew/.linuxbrew/

安装软件

brew install pkgname

查找软件可在brew.sh查找,或通过命令查找:

brew search pkgname

进程管理

查看进程

jobs [-lnprs] [jobspec ...] or jobs -x command [args]
#    Display status of jobs.

查看并过滤进程

ps -e|-A  \  # 查看所有进程
   -T|t   \  # 当前终端上的所有进程
   -x     \  # 没有关联控制终端(tty)的进程
   -r     \  # 正在运行的进程 
   -a     \  # 排除关联tty的所有进程或session leader   
   -d     \  # 除了session leader外的所有进程
   -N     \  # --deselect 反选
   H         # 将线程视作进程显示
查找进程
ps -C cmd1,cmd2,... \  # 根据命令名comm筛选
   -p 123,124,... \    # --pid,-q 根据进程号筛选
   -ppid 10       \    # 根据父进程号筛选
   -U EUID        \    # effective user ID (EUID) or name
   -u RUID        \    # real user ID (RUID) or name

-C匹配进程命令起始子串,不包括路径与特殊字符'/-';无法匹配到僵尸进程。

pgrep -f PATTERN  \   # --full 匹配完整进程名
      -x          \   # --exact 完整匹配命令行
      -v          \   # --inverse 反向匹配
      -g PGID,... \   # --pgroup 匹配进程组ID
      -G GID,...  \   # --group 匹配real group IDs
      -i          \   # --ignore-case
      -n          \   # --newest 选择最近启动的进程
      -o          \   # --oldest
      -P PPID,... \   # --parent 匹配父进程ID
      -s SID,...  \   # --sessioin 匹配会话ID
      -u ID,...   \   # --euid 匹配effective user ID
      -U ID,...   \   # --uid 匹配real user ID
      -t TTY,...  \   # --terminal 匹配终端
      --ns PID --nslist ns,...
pgrep -l  \  # --list-name 列出PID和进程名
      -a  \  # --list-full 列出PID和命令行
      -c  \  # --count 输出匹配计数

ps -Cpgrep无法匹配到僵尸进程<defunct>,可以利用ps -ef的输出内容进行匹配。

ps -ef | grep defunct | grep -v grep
输出进程信息
ps -f|-F \  # 完全信息,包括命令行(-F包括附加信息)
   -l    \  # 显示更多信息,可以与-f|-F组合使用
ps -o pid,tid,... \ # 指定输出的字段
   -o '%cpu %mem' \ # 在单个参数中指定输出的字段
   -o class       \ # 可指定多个输出选项
   -o wchan:14    \ # 指定输出字段的位宽
   -o comm=       \ # 该字段不输出字段名(当所有字段都不输出字段名,省略表头)
pid==进程编号==ppid父进程编号
`lwpspidtid`轻量线程ID
`pgidprp`进程组编号tgid
`%cpupcpu`CPU占用率(小数)c
`cputimetime`==累计CPU占用时长==pri
start_time==进程启动时间/日期==start进程启动时间
etime==进程启动后经过的时间==etimes单位为秒
`%mempmem`内存占用比例`vsz
sz进程镜像大小size需要的交换空间大小
`argscmdcommand`命令行参数
`sesssessionsid`会话编号
`ttytttname`控制终端
`fgidfsgid`文件访问组编号`fgroup
`states`stat

进程关联用户信息

realeffectivesaved
用户IDuidruid`euiduid`
用户标识userruser`euseruser
gidrgid`egidgid`
组标识grouprgroup`groupegroup`

需要systemd支持的字段:

  • machine:进程分配到的VM或容器名;
  • ouid:进程会话所有者;
  • lsession:进程的登录会话标识;

其他:

psr:为进程分配的处理器,sgi_p:进程当前运行的处理器;

cgroup:控制组;

class|cls|policy:进程调度类型;sched

blocked|sig_block|sigmask:阻止的信号(32或64位掩码); caught|sig_catch|sigcatch:捕获的信号(32或64位掩码); ignored|sig_ignore, sigignore:忽略的信号(32或64位掩码); pending|sig:挂起的信号(32或64位掩码);

f|flag|flags:进程标识。

进程树
ps  f  \  # 显示为进程树
   -H  \  # 显示进程层级(缩进)
pstree -U     \  # --unicode 使用UTF-8画线符号(默认)表示树
       -A     \  # --ascii 使用ASCII画线符号
       -h     \  # --highlight-all 重点显示当前进程及其祖先进程
       -H PID \  # --highlight-pid 重点显示给定进程及其祖先进程
       -g     \  # --show-pgids 显示进程组标识
       -p     \  # --show-pids 显示进程标识
       -s     \  # --show-parents 显示父进程标识
       -n     \  # --numeric-sort 根据PID对输出排序
       -l     \  # --long 不截断长行
       PID    \  # 进程树根节点的PID,默认为1(init/systemd)
       USER   \  # 显示指定用户的进程树

任务状态

top -b -n N \       # 非交互模式,刷新N次
    -o FIELD[-+] \  # 按字段排序:"+"=>DESC; "-"=>ASC
    -O              # 不执行命令,仅输出可用的排序字段

top命令显示的是你的程序占用的cpu的总数,也就是说如果你是4核cpu那么cpu最高占用率可达400%,top里显示的是把所有使用率加起来。

top的运行环境中按下键盘的1,显示每个cpu核的状态。

交互环境命令

排序:M->Mem, N->PID, P->%cpu, T->TIME+

watch
watch "ps -ef | grep nginx | grep -v grep" \
      -d,--difference        \ # 高亮两次更新的差别
      -n,--interval seconds  \ # 更新周期

watch的命令参数可包含多条命令,输出结果包含每条命令的输出内容。

查看进程打开资源

打开的文件可能是常规文件、文件夹、库、流、网络文件(套接字、NFS文件)等。

lsof   # list open files
lsof /bin/bash
#COMMAND      PID  USER  FD   TYPE DEVICE SIZE/OFF      NODE NAME
#mysqld_sa   1597 mysql txt    REG  253,0   960472 738200678 /usr/bin/bash
#sh         11503    es txt    REG  253,0   960472 738200678 /usr/bin/bash
#bash       16538  yarn txt    REG  253,0   960472 738200678 /usr/bin/bash
#bash       63028  yarn txt    REG  253,0   960472 738200678 /usr/bin/bash

需要安装lsof

fuser [options] file/fs  # identify processes using files or sockets
fuser /bin/bash  # 返回使用文件的进程号与使用方式(后缀)
# /usr/bin/bash:        1597e 11503e 13039e 63028e 63030e 64836e

进程控制

创建进程

nohup &

终止进程

如果父进程在子进程之后终止,但子进程终止时父进程没有进行最后的回收工作,子进程残留的数据结构称为僵尸进程。

终止单个进程

kill向进程发送信号使进程终止,默认信号是-TERM

kill [-s sigspec | -n signum | -sigspec] pid ...
kill -l [sigspec]

sigspec表示信号名,signum表示信号值。

选项说明
-l, --list [sigspec]列出可发送的信号,如果给出信号名(值),
则将信号名(值)转换为信号值(名)
-s sigspec
-n signum
-sigspec
指定发送的信号,例如:-ABRT,-ALRM,-HUP,-KILL,-STOP,-SEGV, -TERM,-TRAP
终止匹配名称的进程
killall [-s sigspec | -sigspec] [-e] [-I] [-g] [-i] [-u user] [-v] [-w] name ...
killall –l

选项

选项说明
-l, --list列出可发送的信号
-s,--signal sigspec
-sigspec
指定发送的信号
-e, --exact匹配名称
-I, --ignore--case匹配名称时忽略大小写
-g, --process-group向进程所属的进程组发送信号
-i, --interactive在杀死进程前交互式确认
-q, --quiet如果没有进程被杀死,不输出信息
-u, --user仅杀死属于给定用户的进程
-v, --verbose报告信号是否成功发送
-w, --wait等待所有被杀死的进程结束
终止匹配的进程
pkill [options] --signal SIGNAL PATTERN
终止图形进程
xkill

出现“x”标志的鼠标,点击需要中止的程序即可。

清理进程

wait -f -n [CH_PID,,,]  # 清理子进程

服务

systemd

systemdsystem and service manager),init system (PID=12, started by the kernel, to bring up userspace) managing userspace services. (fast and efficient boot-up)

sysvinit

/sbin/init -> ../lib/systemd/systemd

system instance: system.conf and the files in system.conf.d

user instance: user.conf and the files in user.conf.d

"units" of 11 different types. states: active/inactive/activating/decativating/failed

Units are named as their configuration files

Processes systemd spawns are placed in individual Linux control groups named after the unit which they belong to in the private systemd hierarchy. /sys/fs/cgroup/systemd/

transaction system: before executing a requested operation, systemd will verify that it makes sense, fixing it if possible, and only failing if it really cannot work.

  • Service:管理控制守护进程及其相关进程;

  • Socket:用于提前创建套接字资源。

  • Target:group units(使用Requires,After)。

    default.target whose job is to activate on-boot services and other on-boot units by pulling them in via dependencies. graphical.target/multi-user.target

  • Device:expose kernel devices

  • Mount/Swap:mount points/memory swap(类似于mount命令)

  • Automount

  • Timer:定时触发其他单元;

  • Path

  • Slice:分组资源管理;

  • Scope:管理外部进程

信号处理:

SIGTERM:重启systemd system manager;

SIGINTCtrl+Alt+Del):If this signal is received more than 7 times per 2s, an immediate reboot is triggered.

SIGHUPsystemctl daemon-reload

管理器交互命令可以用于管理服务。systemctl are used to give commands to the manager.

systemctl --version # 查看版本和加载模块
systemctl {start|stop|reload|restart|kill} <service>
systemctl {enable|unmask} --now <service> # 启用并立即启动服务
systemctl {disable|mask} <service>        # 禁用/屏蔽服务
systemctl status <service>
systemctl show <service>
systemctl list-unit-files --type {service|target} # 列出已安装单元
systemctl list-units --type {...}                 # 列出已加载单元
systemctl daemon-reload  # 重新加载服务单元配置(不影响现有服务)

此外,systemdctl还可用于控制系统

systemctl {poweroff|reboot[arg]|suspend|hibernate}

service命令也用用管理服务,在Ubuntu中其实际调用的是systemctl

Systemd 入门教程:命令篇 - 阮一峰的网络日志 (ruanyifeng.com)

管理配置文件

A unit file is a plain text ini-style file that encodes information about a service, socket, device, mount point, automount point, swap file or partition, start-up target, watched file system path, timer controlled and supervised by systemd, resource management slice or group of externally created processes.

服务配置文件(.ini格式)位于/lib/systemd/system(/lib->/usr/lib);systemctl enable会在/etc/systemd/system目录(某些服务也直接置于*.target子目录下)创建一个指向服务单元的链接(也可直接在该目录下储存配置文件或链接其他位置的配置文件,但无法使用enable/disable命令)。

pkg-config systemd --variable=systemdsystemunitdir:系统服务配置文件路径;

pkg-config systemd --variable=systemduserunitdir

不同于其他systemctl命令,==必须以管理员权限执行==systemctl enable|disable以创建或删除服务配置文件的链接。

配置文件名由管理单元名和类型名组成,如unit-name[@instance-name].service服务模板:在配置文件中通过"%i"引用实例名称)。文件格式:key=value=前后空格被忽略;#;为注释行;\用于换行拼接(连接时添加空格,换行符后的注释行被忽略,随后的内容将继续被拼接);

boolean:1,yes,true,on0,no,false,off

time:默认为秒,"2min 200ms", s", "min", "h", "d", "w", "ms", "us".

multiple settings form a list, empty value "resets"

[Unit]
Description=The descript of the service
Documentation=http://,https://,file:,info:,man:,
Wants/Requires/Requisite/BindsTo/PartOf/Upholds=
Conflicts=
Before/After=
After=network.target ... nginx.service mongod.service
[Install]
Alias=sshd.service   # create symlinks 
WantedBy/RequiredBy=multi-user.target

UnitInstall是所有单元类型配置文件共有的部分。

foo.service.d/*.conf:在该目录下添加配置文件覆盖该服务的默认配置。

单元参数说明

  1. 依赖声明:==不影响启动顺序(可并行启动)==
    • Wants=:one-time effect => [Install] WantedBy=foo.service.wants/
      • Requires==> [Install] RequiredBy=
        • Requisite==> RequisiteOf=
        • BindsTo==> BoundBy=
        • PartOf==> ConsistsOf=
      • UpHolds=:continuous effect,
    • Conflicts==> ConflictedBy=
  2. 启动顺序
    • Before=, After=
    • OnFailure=,OnSuccess=

Specifiers available in unit files: https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers

服务单元参数说明

[Service]
Type=simple/exec/forking/oneshot/dbus/notify/idle
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c conf/nginx.conf # 启动前的检测
ExecStart=/usr/local/nginx/sbin/nginx -c conf/nginx.conf       # 启动服务的命令
ExecStartPost=/bin/sleep 1                                     # 启动服务后的命令
ExecReload=/usr/local/nginx/sbin/nginx -s reload               # reload命令
ExecStop=/bin/kill -s TERM $MAINPID                            # stop命令
StandardOutput=syslog
User=service_user
Environment="VAR=VALUE"    "VAR2=VALUE2"
Environment="VAR3=VALUE3"  # 可声明多行环境变量
KillMode=control-group, mixed, process, none
KillSignal=SIGTERM
  1. Type=:服务类型

    • simple(默认):认为ExecStart=配置的进程为服务主进程;当服务主进程被创建后(服务执行程序还未运行)即认为服务启动(即使随后服务启动过程出错,systemctl start仍然报告启动成功)并继续启动后续服务。
      • exec:等待服务进程被执行后才认为服务启动(systemd 219版本不支持,245版本支持该类型);
        • notify:类似于exec,但服务启动后需要发送一个通知消息,服务管理在收到通知消息后,认为服务启动完成并继续启动后续服务;设置NotifyAccess=以访问systemd提供的通知套接字。
      • oneshot:类似于simple,服务主进程退出后即认为服务启动完成,通常用于设置==开机启动任务==;RemainAfterExit=yes用于表示服务在启动完成后进入active状态,否则,由于没有配置持续运行的进程,服务状态将变为deactivatingdead状态。
      • dbus:类似于simple,服务获得一个D-Bus总线名(BusName=)后,即认为完成启动;默认依赖dbus.socket
      • idle:类似于simple,但会延迟服务程序的执行时间(最多5s),直到活动任务被执行。
    • forkingExecStart=配置的进程会调用fork()来启动后台服务(Unix服务启动协议)。父进程在后台进程启动完成后退出,服务管理认为服务启动完成。==如果服务自身可以输出主进程ID到文件,则推荐使用PIDFile=选项==,使得systemd能够可靠地识别服务主进程从而判断服务状态 。如果未设置PIDFile,则默认GuessMainPID=yes以尝试获取服务主进程ID,但如果服务存在多个守护进程,则不一定准确。

    对于长期运行服务,首先推荐使用简单且快速的Type=simlpe。但如果需要获取服务启动状态,或其他服务依赖此服务,则推荐使用notifydbus;如果服务程序并不支持notifydbus,则使用forking。对于==仅启动时执行一次==的服务,则可以使用oneshot

  2. 服务单元执行环境配置

    1. RootDirectory=(chroot)

    2. WorkingDirectory=

    3. User=, Group=

    4. 进程资源限制ulimitLimitCPU/LimitFSIZE/LimitNOFILE...

    5. CPU调度策略:CPUSchedulingPolicy/CPUAffinity...

    6. Environment=,EnvironmentFile=:定义传递给服务的环境变量(定义不支持Shell变量替换,重复定义将替换之前的定义);

      • $PATH:默认值/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
      • $MAINPID:服务主进程ID,用于管理服务控制进程的关闭和重载;
      • $PIDFILE:通过PIDFile=传递,用于服务守护进程写入进程ID;
    7. StandardInput=,StandardOutput=,StandardError=inherit, null, tty, kmsg, journal+console, kmsg+console, socket or fd:name.

      • journal:发送到journal,输出日志通过journalctl查看
      • syslog:发送到系统的syslog服务和journal。
      • file:path(v236+), append:path(v240+), truncate:path:输出到指定文件(219版本不支持,对于不支持的版本使用文件重定向标准输出)。

      systemd管理的服务产生的日志可通过journalctl查看。

      journalctl [FIELD=VALUE...] \ # 未添加匹配条件则返回所有日志 systemd.journal-fields
          --options
      
    8. SyslogIdentifier=,SyslogFacility=,SyslogLevel=

  3. ExecStart=:服务启动命令。==除非是oneshot类型==,否则仅能给定一条命令。==命令必须以可执行程序的绝对路径开头==(对于其他Exec命令也一样)。

    systemd-path search-binaries-default:如果返回路径,则表示支持直接使用位于路径的命令名。

    命令参数支持环境变量替换:${VARIABLE}始终解释为一个参数,$VARIABLE必须与命令行==其他内容使用空格分开==(否则不会展开),展开后会按空白分割为多个参数;

    支持Systemd定义的%特殊变量。

    --opt1 $VARIABLE1  --opt2=${VARIABLE2}
    # --opt2=$VARIABLE3 无法完成变量替换
    

    命令中不能包含重定向(<,<<,>,>>)、管道(|)和后台执行(&)等Shell语法。显式使用bash命令

    ExecStart=bash -c 'dmesg | tac'
    

    命令前缀:

    • -:记非零错误返回,但处理行为等效于命令成功执行;
    • ::不替换命令行环境变量;
    • "+"以完整权限执行,不受用户和分组设置限制;
  4. ExecStartPre=, ExecStartPost=:类似于ExecStart=:,分别在ExecStart=:前后执行,并可指定多条命令。ExecStart=仅在ExecStartPre=执行成功的情况下执行,否则服务启动失败(ExecStartPost=类似)。ExecStartPre=不应用于启动长期运行程序(ExecStartPre=启动进程所创建的子进程会在服务程序执行前被终止)。任何Exec*=命令执行失败或超时,则会跳转到执行ExecStopPost(跳过ExecStop=)。

  5. ExecReload=:服务重新加载配置的一条或多条命令(语法类似于ExecStart=)。

  6. ExecStop=,ExecStopPost=:停止服务的一条或多条命令。如果未指定,则向服务发送``KillSignal=RestartKillSignal=`指定的信号以终止服务进程。

  7. TimeoutSec=,RestartSec=,TimeoutStartSec=,TimeoutStopSec=服务启动/停止超时期限。

  8. Restart=no|on-success|on-failure|on-abnormal|on-watchdog|on-abort|always

  9. SuccessExitStatus=TEMPFAIL 250 SIGKILL:成功退出状态,默认包括0SIGHUPSIGINTSIGTERMSIGPIPE

systemd.service (www.freedesktop.org)

服务沙盒

以下选项用于屏蔽向服务进程暴露的系统资源(需要底层安全机制支持才开启,如ProtectSystem需要包含文件系统命名空间的内核)。

ProtectSystem=false|true|full|strict*
ProtectHome=false|true|read-only|tmpfs
PrivateTmp=false|true

*stricttmpfs219版本(CentOS 7)不可用。

  • [Mastering systemd: Securing and sandboxing applications and services | Enable Sysadmin (redhat.com)](https://www.redhat.com/sysadmin/mastering-systemd#:~:text=Systemd provides a significant number of security features,this option to full also makes %2Fetc read-only.)
  • systemd.exec Sandboxing(www.freedesktop.org)

问题:

  • 开启ProtectSystem后无法对用户家目录进行写操作。

    如果使用普通用户运行服务,则不用担心该服务修改系统资源(无权限)。因此,可以关闭ProctectSystem选项。也可尝试将服务的写入目录修改为其他位置,例如/tmp/var(适用于以root运行的服务)。

挂载单元配置
[Mount]
What=/dev/DEVNAME
Where=/mnt/MOUNT_PATH
Type=fs_type
Options=
DirectoryMode=0755  # 自动创建挂载点
TimeoutSec=
# Check systemd.exec(5) and systemd.kill(5) for more settings.
定时单元器配置
[Timer]
OnActiveSec/OnUnitActiveSec=   # 相对定时器(执行单元)上次触发时间设置定时器
OnUnitInactiveSec=             # 相对定时器执行单元上次休眠时间设置定时器
OnCalendar=                    # systemd.time(7) 
Unit=                          # 定时器超时后触发的单元名称

supervisor

Introduction — Supervisor 4.2.2 documentation (supervisord.org)

Supervisor is a client/server system that allows its users to control a number of processes on UNIX-like operating systems. It is not meant to be run as a substitute for init as “process id 1”. Instead it is meant to be used to ==control processes related to a project or a customer==,

supervisord starts processes as its subprocesses via fork/exec and subprocesses don’t daemonize. It always knows the true up/down status of its children. If supervisord is started as root, it is possible to allow “normal” users to control (“stop”, “start”, and “restart” ) such processes.

client/server system

delegation: Supervisorctl allows a very limited form of access to the machine, essentially allowing users to see process status and control supervisord-controlled subprocesses by emitting “stop”, “start”, and “restart” commands from a simple shell or web UI.

/etc/supervisord.conf

supervisord -c conf_file
            -n, --nodaemon
            -q ,--childlogdir=PATH # must exist, for auto-mode child proocess
            -k, --nocleanup  # prevent removal of old AUTO process log files    
supervisorctl -c conf_file
              -i,--interactive   # 启动交互式命令
              -r,--history-file  # 记录输入命令(realine模块可用)
              ACTION args...
ACTION:
  add/update NAME[:*]... # activate/update process/group config 
  remove NAME ...        # deactivate process config
  clear NAME ...         # clear process log 
  pid [NAME]             # get pid of supervisord/subprocess
  reload                 # restart remote supervisord
  reread                 # reload daemon's config without restart
  start NAME[:*]...      # start process/group (not reread configs)
  restart NAME[:*]...    # restart process/group (not reread configs)
  status [NAME[:*]...]   # 返回进程(组)状态
  tail [-f] NAME [stdout|stderr] # 输出日志的最后部分

all用于参数中表示所有进程和分组。

supervisord as a system service
# supervisord service for systemd (CentOS 7.0+)
[Unit]
Description=Supervisor daemon
[Service]
Type=forking
ExecStart=/usr/bin/supervisord
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
supervisord
[supervisord]
logfile=$CWD/supervisord.log # (-l,--logfile=FILE)
logfile_maxbytes=50MB  # rotate limit (-y,--logfile_maxbytes=BYTES)
logfile_backups=10     # number of rotates (-z,--logfile_backups=NUM)
loglevel=info          # (-e,--loglevel=LEVEL)
pidfile=$CWD/supervisord.pid # (-j,--pidfile=FILE)
directory=$PWD         # workdir of supervisord daemon (-d,--directory=PATH)
environment=KEY="val",KEY2="val2" # for all subprocess

信号处理:

  • SIGTERM/SIGINT/SIGQUITsupervisord及其管理的子进程将会关闭。
  • SIGHUP:关闭所有进程,重新加载配置,并重启所有进程。
  • SIGUSR2:关闭并重新打开主日志以及子进程日志。
服务进程配置
[program:SERVICE_NAME]
command=/path/to/programname  # relative is OK
user=gary                     # 启动进程的用户
numprocs=1
priority=999                  # Lower priorities indicate programs that start first
autostart=true                # start with supervisord
autorestart=unexpected        # false, unexpected, or true
startsecs=1                   # 0不检查是否进程在运行
startretries=3
exitcodes=0                   # 正常退出代码(,分隔)
stopwaitsecs=10               # 进程停止等待时间(超时使用SIGKILL强制停止)
stopasgroup=false             # 用于停止具有子进程的进程(如Flask调试模式)
stdout_logfile=AUTO           # 进程的标准输出文件
stdout_logfile_maxbytes=50MB  # 日志文件轮转大小
stdout_logfile_backups=10     # 日志轮转数量限制
stderr_logfile=AUTO           # stderr_logfile_maxbytes/stderr_logfile_backups
stdout_syslog=10              # 使用进程名输出到syslog / stderr_syslog
redirect_stderr=false         # 将进程的错误输出重定向到supervisord的输出
environment=                  # 传递给进程的环境变量
directory=                    # 进程运行的工作目录

服务进程本身不应该以守护进程模式运行。

自动重启:如果autorestart=unexpected,则在非手动停止进程的情况下,如果进程退出代码非exitcodes列出的,则重启该进程。

AUTO log files and their backups will be deleted when supervisord restarts.

输出文件名为可包含变量group_name, host_node_name, process_num, program_namehere的Python字符串表达式。

Subprocess State Transition Graph

服务分组:同类型服务;

[group:foo]
programs=bar,baz
priority=999
supervisorctl访问supervisord

supervisorctl可访问本地(UNIX套接字)或远程的supervisord服务(TCP/IP套接字)。

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock  # (-s,--serverurl URL)
# serverurl=http://127.0.0.1:9001
username=gary        # (-u,--username NAME)
password=gang2019    # (-p,--password)
prompt=mysupervisor  # 命令行提示符
使用Web访问supervisord
[inet_http_server]
port=0.0.0.0:9001
username=gary
password=gang2019  # or passord hash: {SHA}82ab876d1387bfafe46cc1c8a2ef074eae50cb1d

重启supervisor(使用systemctl)。

XML-RPC接口
from xmlrpc.client import ServerProxy
server = ServerProxy('http://localhost:9001/RPC2')
server.supervisor.getState()
server.system.listMethods()
server.system.methodHelp('supervisor.shutdown')
子配置文件
[include]
files=/path/filename.conf /path/*.conf foo.conf config??.conf

XML-RPC API Documentation — Supervisor 4.2.2 documentation (supervisord.org)

Supervisor: A Process Control System — Supervisor 4.2.4 documentation (supervisord.org)

Process Monitoring and Events

Supervisor continually emits event notifications, and the subscribed listener will be notified.

provide a mechanism for code to be run (e.g. send an email, make an HTTP request, etc) when some condition related to subprocess state is met.

The event notification protocol is based on communication via a subprocess’ stdin and stdout.

Example Event Listener Implementation

服务管理程序对比

supervisord主要用于管理用户服务进程,systemd处理服务管理外,还支持系统中其他对象如外部设备、套接字、定时器等的管理。

systemd具有启动依赖管理控制功能,可以实现有依赖关系的一组对象的正确启动和运行管理;supervisord仅支持进程分组,无依赖解析功能。systemd具有完善的进程资源控制和系统调度策略设置,supervisor可实现较为简单的资源控制。

supervisord提供网络访问接口并有可用的Web访问UI,可方便普通用户实现进程管理;systemd需要管理权限执行管理控制功能。

superivord发布于2004年,systemd发布于2010年。systemd现在为多数Linux发行版的init程序,因此开箱即用。supervisord需要以Python库或发行版软件仓库软件的方式进行安装。

对于较为简单的服务进程配置管理,supervisordsystemd都能有效实现;对于有远程管理需求的场景,supervisord提供网络访问接口更适合。对于复杂的服务配置管控需求以及supervisor不支持的管控对象,使用systemd更加合适。

网络管理

网络管理工具

net-tools:包含arp, ifconfig, netstat, rarp, nameif and route

ipshow/manipulate routing, network devices, interfaces and tunnels,代替net-tools

NetworkManager:包含NetworkManager服务和命令行工具nmclinmtui等。

与使用ip的功能相同,使用nmcli+NetworkManager将管理功能与用户交互分离。

networkd

NetworkManager

NetworkManager用于代替已有的配置工具ifconfig及其配置文件。NetworkManager作为systemd服务运行(服务的配置文件为/etc/NetworkManager/NetworkManager.conf)。

udev设备管理器发现系统新加入设备,通知NetworkManager通过D-Bus来检测和初始化配置网络设备实现即插即用(配置信息动态生成并存储于内存中)。

永久配置文件检查(如果未找到配置文件,则尝试从DHCP服务器获取配置信息):

  • etc/sysconfig/network-scripts/ifcfg-*:后向兼容ifconfig配置文件;

  • /etc/NetworkManager/system-connections/NetworkManager配置文件。

nmcli是NetworkManger的命令行工具(客户端),nmtui是对应的终端图形界面工具。

yum install NetworkManaget-tui  # nmcli随NetworkManager安装

图形化配置接口:

nmtui edit <ifname>    # in CentOS

在修改配置时,不要修改设备(00:0C:29:BD:83:63 (ens32)

网络状态

主机名和域名

hostname可以读取主机的主机名、域名和对应的IP地址(/etc/hostname)。

  • -A:所有主机名;-s返回一个短主机名;-f返回长主机名;
  • -I:所有IP地址;-i还首先读取IPv6地址;
  • -d:DNS域名;

使用hostnamectl设置主机名。

域名地址映射*
dig [@dns_server] domain_name
dig -x ip_addr   # reverse lookup
nslookup <domain>

支持反向查询nslookup <ipaddr>,但查询到的域名不是通常使用的域名,也可能查不到结果。

whois <ipaddr|domain>     # sudo apt install whois

查询IP地址/域名==所有者==。

网络接口信息

nmcli   # 代替ifconfig
netstat -i  # 输出网络接口设备的统计信息;
        -ie # => ifconfig

使用ip工具列出设备参数(type,mtu,qdisc,state,mode,qlen,mac):

ip link [show] [up|down] [dev eth0] [type bridge] [master br0] # 显示链路信息
ip address ...   # 显示链路层以及网络地址信息

使用nmcli查看网络接口连接:

nmcli c[onnection] [show] --active # summary table
# NAME  UUID                                  TYPE      DEVICE
# eth0  cb149a11-edae-3f8f-9af1-7dc541e1ac5d  ethernet  ens32
nmcli connection show <name/id>  # interface details

设备未知的接口通常是由于配置文件存在错误。

查看网络设备信息:

nmcli d[evice] [show] # summary table
# DEVICE  TYPE      STATE      CONNECTION
# ens33   ethernet  connected  ens33
# lo      loopback  unmanaged  --
nmcli device show <device> # device details

网络通信状态信息

netstat -a      # 列出tcp,udp和unix协议套接字连接(默认仅显示unix套接字连接) *
        -{t|u}  # 只列出TCP/UDP连接
        -l      # 只列出监听中的连接
        -p      # 列出进程ID和命令名
        -e      # 列出进程用户和进程文件的Inode编号
        -n      # 禁用对IP地址/端口的反向域名解析,加快查询速度

*:需要安装net-tools包。

示例:

sudo netstat -anp | grep ESTABLISHED   # 打印active状态的连接
sudo netstat -anp | grep apache2       # 查看指定服务是否正常运行

通过访问套接字获取连接信息:

ss -n   # 禁止解析服务名称
   -r   # 尝试解析地址端口信息
   -a/l # 显示所有/监听套接字信息 
   -m   # 显示套接字内存占用
   -p   # 显示使用套接字的进程
   -e   # 显示扩展信息
   -i   # 显示TCP内部信息
   -s   # 打印汇总信息
   -N,--net=NSNAME # 切换网络命名空间
   -f,--family=unix/inet/inet6/link/netlink/vsock

由于网络连接(套接字)是特殊文件,因此可以使用lsof查看(lsof用于列举进程打开的文件)。

lsof -i -P -n
  • -i [addr]:列出使用互联网地址的文件(套接字);地址格式

    [46][protocol][@hostname|hostaddr][:service|port]

  • -U 筛选使用UNIX套接字的进程。

  • -P:禁止将端口号解析为服务名;

  • -n:禁止将IP地址解析为主机名或域名。

网络协议统计信息
netstat -s
监控网络通信状态
iftop   # apt|yum install iftop  => 主机间通信速率
nload   # apt|yum install nload  => 网络接口通信统计
bmon    # apt|yum install bmon   => 系统带宽监控
nethogs # yum install nethogs    => 进程通信统计

系统监控工具也可以监控网络通信状态的基本参数。

网络可达性检测

pingis part of iputils package

ping \             # ICMP ECHO_REQUEST
     -4|6  \       # IPv4/IPv6
     -c count \ 
     -D            # print timestamp before each line
     -I interface  # 设置源地址或源接口名称

tracepathis part of iputils package.

tracepath -4|6 -n|b # n|b 仅打印IP地址/打印主机名和IP地址

网络设备链路管理

网络配置数据

系统中可能存在的网络设备和接口配置文件:

  • ifup/ifdown/etc/network/interfaces

  • networkd

    [connection]
    id=br0_eno1
    uuid=ccfcb8fa-5f16-4407-ae6c-1af6c9117265
    type=bridge
    autoconnect=false
    interface-name=br0_eno1
    permissions=
    timestamp=1650420144
    [bridge]
    stp=false
    [ipv4]
    address1=172.28.76.22/24,172.28.76.234
    dns=172.28.28.28;223.5.5.5;
    dns-priority=100
    dns-search=
    method=manual
    [ipv6]
    addr-gen-mode=stable-privacy
    dns-priority=100
    dns-search=
    method=link-local
    [proxy]
    
  • ifconfigetc/sysconfig/network-scripts/ifcfg-*

    TYPE=Ethernet
    NAME=eth0                # 应该和配置文件后缀匹配
    DEVICE=ens33             # 绑定的设备名
    UUID=a016f249-6703-42eb-a207-e40f80de212f # 绑定的设备UUID
    HWADDR=84:16:f9:03:fd:85 # 绑定的设备MAC(old)
    IPADDR=192.168.2.203
    PREFIX=24                # <-> NETMASK
    GATEWAY=192.168.178.2
    DNS1=223.5.5.5
    DNS2=8.8.8.8
    ONBOOT=yes
    BOOTPROTO=static  # dhcp|bootp|none|static
    
  • NetworkManager/etc/NetworkManager/system-connections

netplan

netplan在系统启动早期将配置信息解析并提供给系统的网络管理服务(如NetworkManager)。

  • 默认由systemd-networkd管理网络设备,其他服务如NetworkManager可替代其功能。

netplan配置文件位于 /{lib,etc,run}/netplan/*.yaml

  • 对于不同目录下的同名配置文件,仅读取最高优先级目录下的文件(/run>/etc>/lib);
  • 对于不同名文件,将按文件名字典顺序读取配置文件,并将新内容追加/覆盖已读取内容。

配置文件格式(YAML):

network:  # 网络配置的根节点
    renderer: networkd|NetworkManager  #  networking backend, 
    ethernets:  # 设备分组, 如: ethernet, modem, wifi
        ens33:  # 设备ID
            dhcp4: false
            dhcp6: true
            addresses:
                - 192.168.0.200/24 # IPv4
                    lifetime: 0
                    label: "maas"
                - "2001:1::1/64"   # IPv6
            gateway4: 192.168.0.1  #! deprecated
            gateway6: "2001:4::1"  #! deprecated
            routes:   # 静态路由*
                - to: default # could be 0/0 or 0.0.0.0/0 optionally 默认路由
                  via: 192.168.0.1  # 默认网关
                  metric: 100
                  on-link: true
                - to: default # could be ::/0 optionally
                  via: cf02:de:ad:be:ef::2
            nameservers:  # 手动地址配置时设置
                addresses: [ 223.5.5.5, "FEDC::1" ]
                search: [lab, home]  #**
            match:
                macaddress: 52:54:00:6b:3c:58 
            macaddress: 52:54:00:6b:3c:59  # 修改匹配设备的MAC地址
            mtu: 1500   # 修改匹配设备的MAC地址
            
    version: 2

应用配置文件:

sudo netplan generate  # 生成后端配置文件
sudo netplan apply     # 直接应用配置
sudo netplan try       # validate the config and then apply

物理链路管理

创建和删除链路
ip link add \     # 添加虚拟链路
   link DEVICE \  # 指定物理设备(某些链路类型无物理设备,如IP-over-IP)
   name NAME \    # 默认为物理设备名称
   type TYPE \    # 链路类型:bridge,veth,vlan,macvlan,mactap,ip6tnl,gre,...
   index ID       # 链路编号

其他参数包括:mtu,address,broadcast,txqueuelen,numtxqueues,numrxqueues,...

不同类型链路采用不同的数据链路层协议。

ip link delete {dev NAME|group GROUP} type TYPE
nmcli connection add type <type> ifname <ifname> ... # 创建链路
nmcli connection delete <ifname> 
配置链路参数
ip link set [dev NAME] [group GROUP] prop VALUE 
ip address {add|change|replace} IFADDR dev NAME  # 配置IP地址

如果指定了group则修改设备所属分组,如果未指定设备,则修改分组中所有设备的属性。配置了IP地址的链路能够使用IP协议进行通信。

nmcli connection modify <ifname> [+-]ipv4.addresses 192.168.0.58[/24]
nmcli connection modify <ifname> [+-]ipv4.dns 114.114.114.114
nmcli connection modify <ifname> [-]ipv4.gateway 192.168.0.2
# ipv4.method manual must be supplied with address
nmcli connection modify <ifname> ipv4.method manual \
                                 ipv4.addresses 192.168.0.58/24 
nmcli edit <ifname/id>  # 交互式编辑模式,查看和编辑配置项                                 
启用和停用链路
nmcli c reload
nmcli c up <interface>    # if interface exist

虚拟网桥管理

创建和配置虚拟网桥
ip link add BRIDGE_NAME type bridge 
brctl addbr BRIDGE_NAME
nmcli connection add type bridge CONN_NAME BRIDGE_NAME ifname BRIDGE_NAME

Chapter 12. Configuring a network bridge Red Hat Enterprise Linux 8 | Red Hat Customer Portal

将网卡绑定至网桥
ip link set dev IFNAME master BRIDGE_NAME
nmcli connection modify DEVICE_NAME master BRIDGE_NAME
nmcli connection add type ethernet slave-type bridge CONN_NAME DEVICE_NAME ifname IF_NAME master bridge0

虚拟网卡管理

tap网卡
ip tuntap add dev tap1 mode tap

Tap网卡创建是临时的,如果要永久生效,可将上述命令添加到开机启动命令(如rc.local)。

linux - How to make tap interfaces persistent after reboot? - Super User

防火墙

Linux内核使用Netfilter/iptables过滤包,其中iptables为用户交互接口(iptable-services)。

防火墙规则管理

iptables -t,--table TABLE -OP CHAIN rule_spec  # 链名为大写,表名为小写

-t TABLE:指定访问的(省略则查看filter表);

-OP CHAIN:指定访问的(省略链名则查看所有链)及其操作(例如-L FORWARD);

查询规则
iptables -t TABLE -L,--list CHAIN -v -n --line-number -x  # 列出所有规则
iptables -t TABLE -C,--check CHAIN RULE_SPEC  # 检查指定规则是否存在

-n:不反向解析IP地址(显示IP地址而非域名,加快速度); --line,--line-number:显示规则编号; -v:显示更多信息(分组数、字节数等); -x:显示精确的计数,而非经过单位转换的数据。

管理规则
iptables -I,--insert  CHAIN [NUM] RULE -j TARGET # 在表首部插入一条规则
iptables -A,--append  CHAIN       RULE -j TARGET # 在表尾部插入一条规则
iptables -R,--replace CHAIN  NUM  RULE -j TARGET # 替换指定编号的规则
iptables -D,--delete  CHAIN       RULE -j TARGET # 删除匹配条件的规则
iptables -D           CHAIN  NUM                 # 删除指定编号的规则
iptables -F,--flush   CHAIN                      # 清空表中的规则

默认的表为-t filter

添加相同的规则不会覆盖已有规则,可用以下命令修改已有规则的动作:

iptables -t filter -R INPUT 2 <rules> -j <traget>  # 修改指定规则的动作

必须指定要修改规则的条件,否则该规则的条件将变为默认值(例如IP将变为anywhere)。

修改默认策略

iptables -t filter -P FORWARD DROP
黑白名单机制

黑名单:将默认策略设置为ACCEPT;在规则中添加阻止策略。

白名单:将默认策略设置为DROP,在规则中添加允许策略。

默认策略设置为DROP的缺点:在对应的链中没有设置任何规则时,管理员也会把自己拒之门外;即使对应的链中存在放行规则,当不小心使用"iptables -F"清空规则时,放行规则被删除,则所有数据包都无法进入。所以,如果想要使用"白名单"的机制,最好将链的默认策略保持为"ACCEPT",然后将"拒绝所有请求"这条规则放在链的尾部,将"放行规则"放在前面,这样做,既能实现"白名单"机制,又能保证在规则被清空时,管理员还有机会连接到主机。

自定义链

自定义链仅对应一种类型的表,自定义链中规则配置方式与默认链相同。

iptables -t filter -N,--new-chain IN_WEB   # 创建用于filter表的自定义链
iptables -E,--rename-chain IN_WEB WEB      # 重命名
iptables -X,--delete-chain WEB             # 删除自定义链,需未被引用且不包含任何规则
iptables -t filter -I INPUT RULE -j IN_WEB # 引用自定义链
保存规则

通过iptables对规则的修改并非永久生效,当重启iptables服务或者重启服务器以后规则便失效了。如果想要修改永久生效,必须使用service iptables save保存规则,如果误操作了规则但是并没有保存,那么使用service iptables restart命令重启iptables以后即恢复修改前的状态。

目前的发现版多数已用防火墙软件(如CentOS/firewallUbuntu/ufw)代替了iptable-services了,因此使用上述方法需要安装该服务。

iptables-save     # 将防火墙规则导出到标准输出
iptables-restore  # 从标准输入导入防火墙规则

包匹配条件

多个条件之间具有AND关系,使用!对条件取反。

基本匹配条件

# IP地址
-s sip1,sip2 -d dip1
-s ip/mask
# 协议类型
-p tcp # all, tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh
# 网卡接口
-i eth0 -o eth1

-i选项只能用于上图中的PREROUTING链、INPUT链、FORWARD链;-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链。

扩展匹配条件:由netfilter的扩展模块处理的条件。

# 端口
-m tcp --sport 1:1024 --dport 22     # 需要指定扩展模块tcp, udp, icmp
-m tcp --sport :1024 --dport 10000:  # 可省略一个端口边界参数
-m multiport --dports 22,36,80:100
# IP范围
-m iprange --src-range 192.168.1.127-192.168.1.146  # --dst-range
# 字符串:匹配报文中包含的字符串
-m string --algo bm --string xyz
# time
-m time --datestart 2017-12-24 --datestop 2017-12-27
-m time --timestart 09:00:00 --timestop 18:00:00
-m time --weekdays 6,7 --monthdays 22,23

当扩展模块的名称与协议名称相同的情况下,如果已经指定了协议,则可以省略模块选项。

--algo指定字符串匹配算法,可选算法有bmkmp

# connlimit 限制连接数量
-m connlimit --connlimit-above 2 --connlimit-mask 24 -j DROP

--connlimit-mask表示对一个网段施加连接数限制(未指定时为对每个IP的连接数进行限制)

# limit 使用令牌桶限制报文速率
-p icmp -m limit --limit 10/minute -j ACCEPT
-p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT

--limit:报文允许的速率(令牌的生成速率,单位可以是second,minute,hour,day); --limit-burst:允许的突发流量(令牌桶的容量,默认值为5);

需要添加一条默认DROP/REJECT的规则,以丢弃超过速率限制的包。

其他扩展条件:tcp-flagsstate

http://www.zsythink.net/archives/1578

动作

REJECT可以附加发送一个ICMP响应报文。

-j REJCT --reject-with icmp-host-unreachable
-j LOG --log-prefix "logname" --log-level alert

LOG动作默认将报文的相关信息记录在/var/log/message文件中,通过修改/etc/rsyslog.conf(或/etc/syslog.conf),

kern.warning /var/log/iptables.log

--log-levelemergalertcriterrorwarningnoticeinfodebug

端口管理

sudo vi /etc/sysconfig/iptables
端口权限

小于1024的端口号(特权端口)不允许非root用户打开,以防恶意程序占用这些端口建立恶意服务。

如果用户需要使用这些端口,解决方法包括:

  1. 使用Apache或nginx作为代理服务器;

  2. 使用iptables设置防火墙规则,使得低端口在内部自动转发至高端口

  3. jsvc

  4. authbind

  5. 设置文件打开端口的权限

    sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary
    

路由配置

转发功能

开启防火墙的转发功能。

echo 1 > /proc/sys/net/ipv4/ip_forward  # 设置为1开启转发,0关闭转发
sysctl -w net.ipv4.ip_foward=1

上述方式为设置系统运行时变量,要永久生效需要修改系统配置。

Ubuntu使用ufw管理防火墙规则,其配置文件在/etc/ufw/sysctl.conf,其中对应的配置项为:

net/ipv4/ip_forward=1
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

CentOS7中配置/usr/lib/sysctl.d/00-system.conf,并设置net.ipv4.ip_forward=1

设置防火墙转发规则

iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

NAT

# SNAT: 将源内网地址映射到公网地址
iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -o eth0 -j SNAT --to-source 192.168.1.146 
# 动态SNAT: 动态将源内网地址映射到动态变化的公网地址
iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -o eth0 -j MASQUERADE 
# DNAT: 将目的公网地址+端口映射到内网地址+端口
iptables -t nat -I PREROUTING \
  -d 192.168.1.146 -p tcp --dport 3389 -j DNAT --to-destination 10.1.0.6:3389

DNAT在理论上只配置DNAT规则即可,但是如果在测试时无法正常DNAT,可以尝试增加对应的SNAT,此处按照配置SNAT的流程进行。

如果没有动态SNAT的需求,没有必要使用MASQUERADE,因为SNAT更加高效。

本机端口转发
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 # INPUT
iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8080      # LOCAL
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1186 -j DNAT --to-destination 127.0.0.1:1186

将访问本机80端口的请求重定向到本机的8080端口(修改目标端口)。

如果要从外部访问本机localhost监听的端口,可使用DNAT将地址和端口映射到本机换回地址和相应端口(需要开启本地换回路由:sysctl -w net.ipv4.conf.<ifname>.route_localnet=1ifname为输入网络接口)。

路由表

获取路由信息
ip {r|route}
#default via 192.168.178.2 dev ens32 proto static
#default via 172.28.76.234 dev ens33 scope link metric 1
#172.28.76.0/24 dev ens33 proto kernel scope link src 172.28.76.234
#192.168.178.0/24 dev ens32 proto kernel scope link src 192.168.178.40

表格形式:

route [-nee]   
#Destination    Gateway        Genmask       Flags  Metric ...  Iface
#0.0.0.0        192.168.178.2  0.0.0.0        UG      0    ...  ens32
#0.0.0.0        172.28.76.234  0.0.0.0        UG      1    ...  ens33
#172.28.76.0    0.0.0.0        255.255.255.0  U       0    ...  ens33
#192.168.178.0  0.0.0.0        255.255.255.0  U       0    ...  ens32
netstat -r -n
#Kernel IP routing table
#Destination    Gateway        Genmask        Flags MSS Window irtt Iface
#0.0.0.0        172.28.76.234  0.0.0.0        UG      0 0         0 ens33
#172.28.76.0    0.0.0.0        255.255.255.0  U       0 0         0 ens33

ee:显示更多信息。

  • 路由类型

    主机路由:掩码为32位; 网络路由: 默认路由:目标为0.0.0.0/0.0.0.0。当主机不能在路由表中查找到目标主机的IP地址或网络路由时,数据包就被发送到默认路由(默认网关)上。

  • Flags说明: U (route is up):活动路由; H (target is host):目的地址是主机; G (use gateway): 需要网关转发;

  • Metric:路由距离,到达指定网络所需的中转数。

  • Iface: 当前路由会使用哪个接口来发送数据

配置静态路由
route [add|del] [-net | -host] target [netmask Nm] [gw Gw] [[dev] If]
route add default gw 192.168.1.1
route add -net 5.0.0.0 netmask 255.0.0.0 reject # 设置到指定网络为不可达

没有修改已有路由的命令(例如修改metric),需要先删除再添加一条。

上述命令仅在当前运行环境中有效,要永久保存需要将其添加至文件中。可直接在在/etc/rc.local中添加上述命令,则开机会自动添加静态路由,但如果开机状态下重启网络服务则不会再次执行/etc/rc.local,导致静态路由失效。

另一种方式是编辑/etc/sysconfig/static-routes(CentOS/Fedora),该文件由网络服务自动加载。

any -net 192.56.76.0 netmask 255.255.255.0 dev eth0

any开头的行将被解释为静态路由项。

Ubuntu静态路由配置?

ip工具包用于替换route等管理工具:

ip route {add|del|change|append|replace} ROUTE
#  ROUTE= [TYPE] NETWORK/MASK [via [FAMILY] GW_IP] [dev DEVICE] [weight NUM]
ip route add default via 192.168.1.1 dev eth0  # 设置默认路由

TYPE:路由类型,包括unicast,mulitcast,broadcast,nat,local,...

FAMILY:协议族: inet,inet6,mpls,bridge,link

本地网络代理

可配置系统范围(/etc/environment)或用户范围(~/.bashrc~/.profile)。

export http_proxy="http://USERNAME:PASSWORD@proxy.server.net:port/"
export https_proxy="http://proxy.server.net:port/"
export ftp_proxy="http://proxy.server.net:port/"
export no_proxy="localhost, 127.0.0.1, 192.168.178.4"  #*

*no_proxy不支持通配符,如果要写一个网段,只能逐个地址列出。no_proxy主要用于匹配域名后缀,而非IP地址(前缀)

如果是系统范围代理,还需设置/etc/sudoers.d/proxy,避免环境变量被覆盖。

Defaults env_keep+="http_proxy https_proxy no_proxy"

网络服务

systemctl restart networking

常用网络服务

远程访问

X-Window

https://wiki.ubuntu.org.cn/%E7%90%86%E8%A7%A3_Xwindow

安全

内核强制访问控制

Both SELinux and AppArmor supports the Type Enforcement security model, which is a type of mandatory access control, based on rules where subjects (processes or users) are allowed to access objects (files, directories, sockets, etc.).

Implementing Mandatory Access Control with SELinux or AppArmor in Linux (tecmint.com)

Security Enhanced Linux

SELinux支持更强的访问控制。

查看SELinux状态:

getenforce
sestatus -v

临时关闭(设置成permissive模式,仅产生日志不进行控制):

sudo setenforce 0	# setenforce 1 => enforcing mode 

永久关闭:

# sudo vi /etc/selinux/config
SELINUX=disabled   # SELINUX=enforcing|permissive|disabled
SELinux策略

查看boolean策略状态:

getsebool -a [se_boolean_entry]

设置boolean策略:

setsebool -PV se_bool_entry value  # (1|true|on,0|false|off)

Apparmor

AppArmor是与SELinux类似的一个访问控制系统,通过它你可以指定程序可以读、写或运行哪些文件,是否可以打开网络端口等。

linux内核强制访问控制--Apparmor - 运维之路 (361way.com)

AppArmor与SELinux - 运维之路 (361way.com)

数字证书

安装证书

系统信任证书目录位于/usr/local/share/ca-certificates。将证书文件置于该目录下,并将权限设置为644

sudo apt install ca-certificates
sudo update ca-certificates   # needs super user privilege

生成证书和私钥

OpenSSL是一个非常有用的开源命令行工具包,可用于 X.509 证书,证书签名请求(CSRs)和加密密钥。

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
openssl x509 -in cert.pem -text -noout  # 查看证书结构信息

key.pem为私钥;cert.pem为证书(包含公钥);生成签名过程设置的密码是在使用密钥的时候使用。

使用私钥和证书需要输入制作时设置的密码。

PEM格式

详细步骤

Create an RSA Keypair:

sudo apt install openssl
openssl genrsa -des3 -passout pass:PASSWORD -out keypair.key 2048

Extract the Private Key:

openssl rsa -passin pass:PASSWORD -in keypair.key -out private.key

Creating a “Certificate Signing Request” or CSR File:

openssl req -new -key private.key -out service.csr

Creating the Certificate “.crt” File:

openssl x509 -req -days 365 -in service.csr -signkey private.key -out service.crt

https://www.rosehosting.com/blog/how-to-generate-a-self-signed-ssl-certificate-on-linux/

https://www.linux.com/tutorials/creating-self-signed-ssl-certificates-apache-linux/

SSL/TLS

权限管理

用户管理

创建用户

useradd -m -c "FULL NAME" -g GROUP USERNAME   # [lowlevel]
adduser --home DIR --shell SHELL --ingroup GROUP USERNAME 

adduser在Debian系发行版上重新封装了底层useradd命令,其他发行版上是useradd的别名。以下均为useradd选项。

有效用户名模式:[a-z_][a-z0-9_-]*[$]?,长度不超过32。

-c "COMMENT":通常用于设置用户名全称;

-s,--shell SHELL 用户的登录shell程序,/etc/default/useradd#SHELLchsh)。

用户目录
  • -b,--base-dir BASE_DIR:用户主目录的根目录路径,默认值为/etc/default/useradd#HOME=/home
  • -d,--home-dir HOME_DIR:用户主目录路径,默认值为$BASE_DIR/USERNAME
  • 使用-m,--create-home保证创建用户目录; -M,--no-create-home不创建用户目录(通常用于运行系统服务的非登录用户);
用户组
  • -g,--gid GROUP:用户的初始登录组(primary group:ID或名称,必须存在)。 如果未指定该选项,默认(/etc/login.defs#USERGROUPS_ENAB=yes)会自动创建与用户名同名的组(等效于指定-U,--create-user-group选项);如果USERGROUPS_ENAB=no,则新用户的主要组设置为/etc/default/useradd#GROUP=100
  • -G,--groups groupname[,...]:将用户添加至组supplementary groups);
账户和密码有效性
  • -f,--inactive DAYS:密码过期后账户被禁用前的天数。
  • -e,--expiredate YYYY-MM-DD:账户失效(禁用)日期,默认值为/etc/default/useradd#EXPIRE=''(不失效);

修改用户

使用usermod修改用户属性(多数属性对应的选项与useradd相同)。

usermod -a,--append -G GROUPNAME  # 将用户添加到supplementary groups
usermod -l,--login NAME # 修改登录名 
usermod -m,--move-home -d,--home HOME  # (移动)修改用户主目录
设置账户有效期限
usermod -e,--expiredate YYYY-MM-DD/N/-1 USER # 设置失效日期*
chage   -E,--expiredate YYYY-MM-DD/N/-1 USER  

*N表示自1970年1月1日的天数。

此外,账户密码失效后账户也会处于失效状态。

设置和更新密码

创建用户时默认禁用密码。使用passwd设置和更新密码(root账号可修改普通用户的密码,用户忘记密码可通过root帐号使用passwd指令来处理即可)。

passwd username
usermod -p,--password ENCRYPT_PASSWORD
passwd -d,--delete  # 删除(置空)用户密码

如果root帐号忘记了,可以进入单人维护模式,此时系统会给予提供root权限的bash接口,再用passwd修改密码;或者利用Live CD开机后挂载根目录去修改/etc/shadow,将root的密码删除,重新开机后再用passwd设置新密码。

密码有效期配置
passwd -e,--expire  # 立即使用户密码失效, 用户必须在下次登录时重设密码
passwd -x,--maxdays  DAYS USER #->chage -M 密码有效期天数(99999/-1)*
passwd -i,--inactive DAYS USER #->chage -I 密码失效后禁用账户前的天数(never)
passwd -n,--mindays  DAYS USER #->chage -m 两次修改密码之间至少相隔的天数(0)
passwd -w,--warndays DAYS USER #->chage -W 需要修改密码前向发送警告的天数(7)

*chage的长选项与passwd对应长选项一致。

显示密码状态:

passwd -S <user>  # 使用-a代替<user>查看所有用户的密码状态。
# gary P 06/02/2022  0 99999 7 -1
chage -l <user>
# Last password change                              : Jun 02, 2022
# Password expires                                  : never
# Password inactive                                 : never
# Account expires                                   : never
# Minimum number of days between password change    : 0
# Maximum number of days between password change    : 99999
# Number of days of warning before password expires : 7

删除用户

userdel -f $USER     # deluser [Debian]
rm -rf /home/$USER

查看用户信息

查系统中的用户信息

/etc/passwd  # User account information.
/etc/shadow  # Secure user account information. [read by root only]

查看当前登录的所有用户:

w
# 09:42:35 up 26 min,  3 users,  load average: 0.18, 0.12, 0.09
#USER  TTY    FROM           LOGIN@   IDLE   JCPU   PCPU WHAT
#root  pts/0  172.28.76.41   09:17    3.00s  0.13s  0.03s w
#root  pts/1  172.28.76.239  09:19   22:45   0.02s  0.02s -bash

who显示的信息没有w完整。who可以显示系统引导终端(tty1)。

查看指定用户信息:

id $USER  
# uid=1000(gary) gid=1000(gary) groups=1000(gary),...(secondary groups)
groups $USER        # 查看用户所属组
username=$(whoami)  # return user name
sudo whoami         # -> root

How to Add User to Group in Linux | Linuxize

组管理

groupadd groupname
groupdel groupname
addgroup [options] [--gid ID] group
sudo usermod -g groupname username      # change user's primary group
sudo usermod -a -G group[,...] username # add user to a secondary group
adduser user group  # add user to grpup

If you omit the -a option, the user will be removed from any groups not listed after the -G option.

sudo gpasswd -d username groupname  # Remove a User From a Group
查看组信息
/etc/group   # Group account information.
/etc/gshadow # Secure group account information.

访问权限控制

访问权限

修改用户访问文件的权限:

chmod [ugoa][+-=][rwxXstugo],... FILE ...
chmod OCTAL-MODE FILE ...

ugoa分别代表文件所有用户,文件同组用户,其他用户和所有用户(省略则默认为a,umask?);+-=表示增加、删除和设置权限。

权限模式:rwxXst中的一个或多个,或ugo中的一个

标识说明标识说明标识说明
r读文件w写文件x访问/执行
s设置用户或组t限制删除X*
u授予所有者权限g授予组用户权限o授予其他组权限

*X表示仅当目标为目录或已经具有其他用户执行权限时,才设置该目标的访问/执行权限。

OCTAL-MODE为1~4数字(取值范围0~7,3bit),第一位代表(设置用户ID,设置组ID和限制删除),其余三位数字分别代表ugo对应的rwx权限。

Ownership

获取对象的所有者信息:

ls -l /opt/360es/ | awk '{print $3,$4}'    # 根据字段位置确定
ls -l /opt/360es/ | sed -n '2,$p' | awk '{printf "user=%s,group=%s\n",$3,$4}'
stat /path/file --format="user=%U group=%G"

从外部(互联网)获取的文件(档案),其所有者信息非本机用户,因此导致本机用户无法正常访问文件,所以需要修改文件的所有者/组

chown -hR owner[:group] FILE
chgrp

--dereference:影响符号链接指向的文件而非符号链接;-h,--no-dereference相反; --from=CURRENT_OWNER:CURRENT_GROUP:仅当文件的当前属性匹配才进行修改; --reference=RFILE:使用RFILE的属性作为修改后的属性; -R:递归修改。符号链接指向的文件夹的遍历规则根据以下选项决定:

  • -H:遍历命令行参数为符号链接锁指向的文件夹;
  • -L:遍历所有符号链接指向的文件夹;
  • -P:步遍历符号链接指向的文件夹(默认)。

提升权限

切换登录用户
su - username # switch user

不支持切换到非登录用户。

以管理员身份运行
sudo \
    -u, --user=user \ # 指定用户执行输入的命令
    -i,--login \      # 使用指定用户登录shell
    [command]         # 运行命令(未指定则切换终端用户)

当前多数发行版默认禁用root账户,并以安装系统期间创建的账户作为管理员。管理员需要使用sudo命令并提供密码以暂时获得root账户权限(使用sudo命令创建的文件其所属用户和组为root)。将其他用户加入sudo用户组使其具有运行sudo的权限。如果要恢复root账户(不推荐),为其设置密码:

sudo passwd root

帮助文档

Linux Manual
  1. 可执行程序和Shell命令;
  2. 系统调用函数文档;
  3. 库函数文档;
  4. 特殊设备文件(通常位于/dev);
  5. 系统内置文件格式和规范(如/etc/passwd);
  6. 游戏;
  7. 其他,如man(7)
  8. 系统管理命令(管理员使用);
  9. 内核过程(非标准)。

急救模式

emergency mode

进入急救模式

  1. GRUB系统选择界面按e进入启动配置项编辑模式;

    linux16 /vmlinuz-....   # 添加rd.break
    
  2. Ctrl+X进入急救模式。

修复磁盘

修复XFS文件系统

由于突然断电,导致XFS文件系统数据损坏。

ls -l /dev/mapper  # 找到dm-0对应的挂载点并卸载设备
umount /dev/mapper/centos-root
xfs_repair -L /dev/mapper/centos-root # 修复该设备
init 6 # 成功修复后重启设备

参考资料