分类 技术 下的文章

控制组可以按照应用管理资源,而不是按照组成应用的单个进程。

 title=

作为一个系统管理员,没有事情比意外地耗尽计算资源让我更觉得沮丧。我曾不止一次填满了一个分区的所有可用磁盘空间、耗尽内存、以及没有足够的 CPU 时间在合理的时间内处理我的任务。资源管理是系统管理员最重要的工作之一。

资源管理的关键是保证所有的进程能够相对公平的访问需要的系统资源。资源管理还包括确保在需要时添加内存、硬盘驱动器空间、还有 CPU 处理能力;或者在无法添加时限制资源的使用。此外,应该阻止独占系统资源的用户,无论其是否有意。

系统管理员可以通过一些工具监控和管理不同的系统资源。例如,top) 和类似的工具允许你监控内存、I/O、存储(磁盘、SSD 等)、网络、交换空间、CPU 的用量等。这些工具,尤其是那些以 CPU 为中心的工具,大部分基于以运行的进程为基本单位进行控制的模型。它们最多只是提供了一种方式来调整 nice 数字,从而修改优先级,或者杀死一个运行的进程。(要了解 nice 数字的信息,查看 使用 Glances 监控 Linux 和 Windows 主机)。

SystemV 环境中基于传统的资源管理的其他工具,由 /etc/security/limits.conf 文件和 /etc/security/limits.d 中的本地配置文件控制。资源可以按照用户或组以一种相对粗糙但实用的方式限制。可以管理的资源包括内存的各个方面、每日的总 CPU 时间、数据总量、优先级、nice 数字、并发登录的数量、进程数、文件大小的最大值等。

使用控制组管理进程

systemd 和 SystemV 之间的一个主要差异是管理进程的方式。SystemV 将每个进程视作一个独立的实体。systemd 将相关的进程集中到一个控制组,简写做 cgroup,并将控制组作为一个整体管理系统资源。这意味着资源能够基于应用管理,而不是由组成应用的各个进程来管理。

控制组的控制单元称作 切片单元 slice unit 。切片是允许 systemd 以树状格式控制程序次序,从而简化管理的概念化。

查看控制组

我将从一些允许你查看不同类型控制组信息的命令开始。 systemctl status <service> 命令显示一个特定服务的切片信息,包括服务的切片。这个例子展示了 at 守护进程:

[root@testvm1 ~]# systemctl status atd.service
● atd.service - Deferred execution scheduler
     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2020-09-23 12:18:24 EDT; 1 day 3h ago
       Docs: man:atd(8)
   Main PID: 1010 (atd)
      Tasks: 1 (limit: 14760)
     Memory: 440.0K
        CPU: 5ms
     CGroup: /system.slice/atd.service
             └─1010 /usr/sbin/atd -f

Sep 23 12:18:24 testvm1.both.org systemd[1]: Started Deferred execution scheduler.
[root@testvm1 ~]#

这是一个我感到 systemd 比 SystemV 和旧的初始化程序更好用的原因的绝佳示例。这里的信息远比 SystemV 能够提供的丰富。CGroup 项包括的层级结构中,system.slice 是 systemd(PID 1),atd.service 在下一层,是 system.slice 的一部分。CGroup 项的第二行还显示了进程 ID(PID)和启动守护进程使用的命令。

systemctl 命令可以列出多个控制组项,--all 参数列出所有的切片,包括当前没有激活的切片:

[root@testvm1 ~]# systemctl -t slice --all
  UNIT                             LOAD   ACTIVE   SUB    DESCRIPTION                    
  -.slice                          loaded active   active Root Slice                      
  system-getty.slice               loaded active   active system-getty.slice              
  system-lvm2\x2dpvscan.slice      loaded active   active system-lvm2\x2dpvscan.slice    
  system-modprobe.slice            loaded active   active system-modprobe.slice          
  system-sshd\x2dkeygen.slice      loaded active   active system-sshd\x2dkeygen.slice    
  system-systemd\x2dcoredump.slice loaded inactive dead   system-systemd\x2dcoredump.slice
  system-systemd\x2dfsck.slice     loaded active   active system-systemd\x2dfsck.slice    
  system.slice                     loaded active   active System Slice                    
  user-0.slice                     loaded active   active User Slice of UID 0            
  user-1000.slice                  loaded active   active User Slice of UID 1000          
  user.slice                       loaded active   active User and Session Slice          

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

11 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
[root@testvm1 ~]#

关于这个数据,第一个需要注意的是数据显示了 UID 0(root)和 UID 1000 的用户切片,UID 1000 是我登录的用户。这里列出了组成每个切片的切片部分,而不是服务。还说明了每个用户登录时都会为其创建一个切片,这为将一个用户的所有任务作为单个控制组项进行管理提供了一种方式。

探索控制组的层次结构

目前为止一切顺利,但是控制组是分层的,所有的服务单元作为其中一个控制组的成员运行。要查看这个层次结构很简单,使用一个旧命令和 systemd 的一个新命令即可。

ps 命令可以用于映射进程的和其所处的控制组层次。注意使用 ps 命令时需要指明想要的数据列。我大幅削减了下面命令的输出数量,但是试图保留足够的数据,以便你能够对自己系统上的输出有所感受:

[root@testvm1 ~]# ps xawf -eo pid,user,cgroup,args
    PID USER     CGROUP                      COMMAND
      2 root     -                           [kthreadd]
      3 root     -                            \_ [rcu_gp]
      4 root     -                            \_ [rcu_par_gp]
      6 root     -                            \_ [kworker/0:0H-kblockd]
      9 root     -                            \_ [mm_percpu_wq]
     10 root     -                            \_ [ksoftirqd/0]
     11 root     -                            \_ [rcu_sched]
     12 root     -                            \_ [migration/0]
     13 root     -                            \_ [cpuhp/0]
     14 root     -                            \_ [cpuhp/1]
<删节>
 625406 root     -                            \_ [kworker/3:0-ata_sff]
 625409 root     -                            \_ [kworker/u8:0-events_unbound]
      1 root     0::/init.scope              /usr/lib/systemd/systemd --switched-root --system --deserialize 30
    588 root     0::/system.slice/systemd-jo /usr/lib/systemd/systemd-journald
    599 root     0::/system.slice/systemd-ud /usr/lib/systemd/systemd-udevd
    741 root     0::/system.slice/auditd.ser /sbin/auditd
    743 root     0::/system.slice/auditd.ser  \_ /usr/sbin/sedispatch
    764 root     0::/system.slice/ModemManag /usr/sbin/ModemManager
    765 root     0::/system.slice/NetworkMan /usr/sbin/NetworkManager --no-daemon
    767 root     0::/system.slice/irqbalance /usr/sbin/irqbalance --foreground
    779 root     0::/system.slice/mcelog.ser /usr/sbin/mcelog --ignorenodev --daemon --foreground
    781 root     0::/system.slice/rngd.servi /sbin/rngd -f
    782 root     0::/system.slice/rsyslog.se /usr/sbin/rsyslogd -n
<删节>
    893 root     0::/system.slice/sshd.servi sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
   1130 root     0::/user.slice/user-0.slice  \_ sshd: root [priv]
   1147 root     0::/user.slice/user-0.slice  |   \_ sshd: root@pts/0
   1148 root     0::/user.slice/user-0.slice  |       \_ -bash
   1321 root     0::/user.slice/user-0.slice  |           \_ screen
   1322 root     0::/user.slice/user-0.slice  |               \_ SCREEN
   1323 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 498801 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.resource-control
 498813 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1351 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 123293 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.slice
 123305 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1380 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625412 root     0::/user.slice/user-0.slice  |                   |   \_ ps xawf -eo pid,user,cgroup,args
 625413 root     0::/user.slice/user-0.slice  |                   |   \_ less
 246795 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625338 root     0::/user.slice/user-0.slice  |                       \_ /usr/bin/mc -P /var/tmp/mc-root/mc.pwd.246795
 625340 root     0::/user.slice/user-0.slice  |                           \_ bash -rcfile .bashrc
   1218 root     0::/user.slice/user-1000.sl  \_ sshd: dboth [priv]
   1233 dboth    0::/user.slice/user-1000.sl      \_ sshd: dboth@pts/1
   1235 dboth    0::/user.slice/user-1000.sl          \_ -bash
<删节>
   1010 root     0::/system.slice/atd.servic /usr/sbin/atd -f
   1011 root     0::/system.slice/crond.serv /usr/sbin/crond -n
   1098 root     0::/system.slice/lxdm.servi /usr/sbin/lxdm-binary
   1106 root     0::/system.slice/lxdm.servi  \_ /usr/libexec/Xorg -background none :0 vt01 -nolisten tcp -novtswitch -auth /var/run/lxdm/lxdm-:0.auth
 370621 root     0::/user.slice/user-1000.sl  \_ /usr/libexec/lxdm-session
 370631 dboth    0::/user.slice/user-1000.sl      \_ xfce4-session
 370841 dboth    0::/user.slice/user-1000.sl          \_ /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
 370911 dboth    0::/user.slice/user-1000.sl          \_ xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
 370930 dboth    0::/user.slice/user-1000.sl          \_ xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
 370942 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libsystray.so 6 23068680 systr
ay Notification Area Area where notification icons appear
 370943 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libpulseaudio-plugin.so 8 2306
8681 pulseaudio PulseAudio Plugin Adjust the audio volume of the PulseAudio sound system
 370944 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libxfce4powermanager.so 9 2306
8682 power-manager-plugin Power Manager Plugin Display the battery levels of your devices and control the brightness of your display
 370945 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libnotification-plugin.so 10 2
3068683 notification-plugin Notification Plugin Notification plugin for the Xfce panel
 370948 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libactions.so 14 23068684 acti
ons Action Buttons Log out, lock or other system actions
 370934 dboth    0::/user.slice/user-1000.sl          \_ Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
 370939 dboth    0::/user.slice/user-1000.sl          \_ xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
 370962 dboth    0::/user.slice/user-1000.sl          \_ nm-applet
<删节>

你可以使用 systemd-cgls 命令查看整个层次结构,这个命令不需要任何的复杂参数,更加简单。

我也大幅缩短了这个树状结构,但是保留了足够多的输出,以便你能够了解在自己的系统上执行这个命令时应该看到的数据总量和条目类型。我在我的一个虚拟机上执行了这个命令,输出大概有 200 行;我的主要工作站的输出大概有 250 行。

[root@testvm1 ~]# systemd-cgls
Control group /:
-.slice
├─user.slice
│ ├─user-0.slice
│ │ ├─session-1.scope
│ │ │ ├─  1130 sshd: root [priv]
│ │ │ ├─  1147 sshd: root@pts/0
│ │ │ ├─  1148 -bash
│ │ │ ├─  1321 screen
│ │ │ ├─  1322 SCREEN
│ │ │ ├─  1323 /bin/bash
│ │ │ ├─  1351 /bin/bash
│ │ │ ├─  1380 /bin/bash
│ │ │ ├─123293 man systemd.slice
│ │ │ ├─123305 less
│ │ │ ├─246795 /bin/bash
│ │ │ ├─371371 man systemd-cgls
│ │ │ ├─371383 less
│ │ │ ├─371469 systemd-cgls
│ │ │ └─371470 less
│ │ └─[email protected] …
│ │   ├─dbus-broker.service
│ │   │ ├─1170 /usr/bin/dbus-broker-launch --scope user
│ │   │ └─1171 dbus-broker --log 4 --controller 12 --machine-id 3bccd1140fca488187f8a1439c832f07 --max-bytes 100000000000000 --max-fds 25000000000000 --max->
│ │   ├─gvfs-daemon.service
│ │   │ └─1173 /usr/libexec/gvfsd
│ │   └─init.scope
│ │     ├─1137 /usr/lib/systemd/systemd --user
│ │     └─1138 (sd-pam)
│ └─user-1000.slice
│   ├─[email protected] …
│   │ ├─dbus\x2d:1.2\x2dorg.xfce.Xfconf.slice
│   │ │ └─dbus-:[email protected]
│   │ │   └─370748 /usr/lib64/xfce4/xfconf/xfconfd
│   │ ├─dbus\x2d:1.2\x2dca.desrt.dconf.slice
│   │ │ └─dbus-:[email protected]
│   │ │   └─371262 /usr/libexec/dconf-service
│   │ ├─dbus-broker.service
│   │ │ ├─1260 /usr/bin/dbus-broker-launch --scope user
│   │ │ └─1261 dbus-broker --log 4 --controller 11 --machine-id
<删节>
│   │ └─gvfs-mtp-volume-monitor.service
│   │   └─370987 /usr/libexec/gvfs-mtp-volume-monitor
│   ├─session-3.scope
│   │ ├─1218 sshd: dboth [priv]
│   │ ├─1233 sshd: dboth@pts/1
│   │ └─1235 -bash
│   └─session-7.scope
│     ├─370621 /usr/libexec/lxdm-session
│     ├─370631 xfce4-session
│     ├─370805 /usr/bin/VBoxClient --clipboard
│     ├─370806 /usr/bin/VBoxClient --clipboard
│     ├─370817 /usr/bin/VBoxClient --seamless
│     ├─370818 /usr/bin/VBoxClient --seamless
│     ├─370824 /usr/bin/VBoxClient --draganddrop
│     ├─370825 /usr/bin/VBoxClient --draganddrop
│     ├─370841 /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
│     ├─370910 /bin/gpg-agent --sh --daemon --write-env-file /home/dboth/.cache/gpg-agent-info
│     ├─370911 xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
│     ├─370923 xfsettingsd --display :0.0 --sm-client-id 261b4a437-3029-461c-9551-68c2c42f4fef
│     ├─370930 xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
│     ├─370934 Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
│     ├─370939 xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
<删节>
└─system.slice
  ├─rngd.service
  │ └─1650 /sbin/rngd -f
  ├─irqbalance.service
  │ └─1631 /usr/sbin/irqbalance --foreground
  ├─fprintd.service
  │ └─303383 /usr/libexec/fprintd
  ├─systemd-udevd.service
  │ └─956 /usr/lib/systemd/systemd-udevd
<删节>
  ├─systemd-journald.service
  │ └─588 /usr/lib/systemd/systemd-journald
  ├─atd.service
  │ └─1010 /usr/sbin/atd -f
  ├─system-dbus\x2d:1.10\x2dorg.freedesktop.problems.slice
  │ └─dbus-:[email protected]
  │   └─371197 /usr/sbin/abrt-dbus -t133
  ├─sshd.service
  │ └─893 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
  ├─vboxservice.service
  │ └─802 /usr/sbin/VBoxService -f
  ├─crond.service
  │ └─1011 /usr/sbin/crond -n
  ├─NetworkManager.service
  │ └─765 /usr/sbin/NetworkManager --no-daemon
  ├─switcheroo-control.service
  │ └─787 /usr/libexec/switcheroo-control
 <删节>

这个树状视图显示了所有的用户和系统切片,以及每个控制组内正在运行的服务和程序。注意叫作 scope(范围)的单元,它将相关的程序组成一个管理单元,在上面列出的结果中就是 user-1000.sliceuser-1000.slice/session-7.scope 控制组包含了 GUI 桌面程序层次结构,以 LXDM 显示管理器会话和其所有的子任务开始,包括像 Bash 命令行解释器和 Thunar GUI 文件管理器之类的程序。

配置文件中不定义范围单元,而是作为启动相关程序组的结果程序化生成的。范围单元不创建或启动作为控制组的组成部分运行的进程。范围内的所有进程都是平等的,没有内部的层次结构。一个范围的生命周期在第一个进程创建时开始,在最后一个进程销毁时结束。

在你的桌面打开多个窗口,比如终端模拟器、LibreOffice、或者任何你想打开的,然后切换到一个可用的虚拟控制台,启动类似 topMidnight Commander 的程序。在主机运行 systemd-cgls 命令,留意整体的层次结构和范围单元。

systemd-cgls 命令提供的控制组层次结构表示(以及组成控制组单元的细节),比我见过的其他任何指令都要完整。和 ps 命令提供的输出相比,我喜欢 systemd-cgls 命令更简洁的树形表示。

来自朋友们的一点帮助

介绍完这些基础知识后,我曾计划过深入研究控制组的更多细节,以及如何使用,但是我在 Opensource.com 的姐妹网站 Enable Sysadmin 上发现了一系列四篇优秀文章,由 Red Hat 公司的 Steve Ovens 所作。与其从头重写 Steve 的文章,我觉得倒不如通过链接到这些文章,利用他的控制组专业知识:

  1. 一个 Linux 系统管理员对控制组的介绍
  2. 如何用 CPUShares 管理控制组
  3. 用更难的方式,手动管理控制组
  4. 用 systemd 管理控制组

像我一样享受这些文章并从中汲取知识吧。

其他资源

互联网上充斥着大量关于 systemd 的信息,但大部分都简短生硬、愚钝、甚至令人误解。除了本文提到的资源,下面的网页提供了关于 systemd 启动更详细可靠的信息。自从我开始这一系列的文章来反映我所做的研究以来,这个的列表已经变长了。

还有一系列针对系统管理员的深度技术文章,由 systemd 的设计者和主要开发者 Lennart Poettering 所作。这些文章写于 2010 年 4 月到 2011 年 9 月之间,但在当下仍然像当时一样有 价值。关于 systemd 及其生态的许多其他优秀的作品都是基于这些文章的。


via: https://opensource.com/article/20/10/cgroups

作者:David Both 选题:lujun9972 译者:YungeG 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

有了 anacron,我可以把脚本和 Ansible 剧本放到合适的地方,以完成各种琐碎的任务。

 title=

自动化是伟大的 IT 和 DevOps 理想,但根据我的经验,可能根本不存在什么不方便的东西。有很多次,我为某些任务想出了一个很好的解决方案,我甚至会编写脚本,但我没有让它真正实现自动化,因为在我工作的机器上不存在易于自动化的基础设施。

我最喜欢的简易自动化工具曾经是 cron 系统,它古老、可靠、面向用户,而且简单(除了一个我永远无法记住的调度语法之外)。然而,cron 的问题是,它假定一台电脑每天 24 小时都在工作。在错过了太多预定的备份之后,我发现了 anacron,一个基于时间戳而非预定时间的 cron 系统。如果你的电脑在通常情况下运行时处于关闭状态,anacron 会确保它在电脑重新开启时运行。创建一个作业只需要简单地把一个 shell 脚本放到三个目录中:cron.daycron.weekly 或者 cron.monthly (如果你想的话,你可以定义更多)。有了 anacron,我发现自己把脚本和 Ansible 剧本用在了各种琐碎的任务中,包括弹出到期和事件提醒。

这是一个现代问题的简单而明显的解决方案,但如果 anacron 没有安装在电脑上,那它对我就没有用。

用 Ansible 进行软件设置

任何时候我设置一台新的计算机,无论是笔记本电脑、工作站还是服务器,我都会安装 anacron。这很简单,但是 anacron 的安装只提供了 anacron 命令。它并没有设置 anacron 的用户环境。所以我创建了一个 Ansible 剧本来设置用户需要什么来使用 anacron 并安装 anacron 命令。

首先,标准的 Ansible 模板:

---
- hosts: localhost
  tasks:

用 Ansible 创建目录

接下来,我创建了用于 Anacron 的目录树。你可以把它看成是一种透明的 crontab。

    - name: create directory tree
      ansible.builtin.file:
        path: "{{ item }}"
        state: directory
      with_items:
        - '~/.local/etc/cron.daily'
        - '~/.local/etc/cron.weekly'
        - '~/.local/etc/cron.monthly'
        - '~/.var/spool/anacron'

这个语法可能看起来有点奇怪,但它实际上是一个循环。with_items: 指令定义了四个要创建的目录,Ansible 在 ansible.buildin.file: 指令中为每个目录迭代一次(目录名填充了 {{ item }} 变量)。与 Ansible 中的一切一样,如果目录已经存在,不会有错误或冲突。

用 Ansible 复制文件

ansible.buildin.copy 模块将文件从一个地方复制到另一个地方。为了让它工作,我需要创建一个叫做 anacrontab 的文件。它不是 Ansible 剧本,所以我把它放在我的 ~/Ansible/data 目录下,那里是我的剧本的支持文件。

  - name: copy anacrontab into place
   ansible.builtin.copy:
    src: ~/Ansible/data/anacrontab
    dest: ~/.local/etc/anacrontab
    mode: '0755'

我的 anacrontab 文件很简单,模仿了一些发行版默认安装在 /etc/anacron 中的文件:

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
1  0  cron.day    run-parts $HOME/.local/etc/cron.daily/
7  0  cron.wek    run-parts $HOME/.local/etc/cron.weekly/
30 0  cron.mon    run-parts $HOME/.local/etc/cron.monthly/

登录时运行 anacron

大多数 Linux 发行版将 anacron 配置为从 /etc/anacron 读取作业。我主要是作为一个普通用户使用 anacron,所以我从我的登录账号 ~/.profile 启动 anacron。我不想让自己记住这些配置,所以我让 Ansible 来做。我使用 ansible.buildin.lineinfile 模块,它会在 ~/.profile 不存在时创建它,并插入 anacron 的启动行。

    - name: add local anacrontab to .profile
      ansible.builtin.lineinfile:
        path: ~/.profile
        regexp: '^/usr/sbin/anacron'
        line: '/usr/sbin/anacron -t ~/.local/etc/anacrontab'
        create: true

用 Ansible 安装 anacron

对于我的大多数系统来说,dnf 模块可以用来安装软件包,但我的工作站运行的是 Slackware(使用 slackpkg),有时不同的 Linux 发行版也会进入我的收藏。ansible.buildin.package 模块提供了一个安装软件包的通用接口,所以我把它用在这个剧本上。幸运的是,我还没有遇到一个名为 anacron 的仓库不是 anacron,所以现在,我不必考虑软件包名称的潜在差异。

这实际上是一个单独的剧本,因为软件包的安装需要权限升级,它由 becomes: true 指令提供。

- hosts: localhost
  become: true
  tasks:
    - name: install anacron
      ansible.builtin.package:
        name: anacron
        state: present

使用 anacron 和 Ansible 实现轻松自动化

为了用 Ansible 安装 anacron,我运行该剧本:

$ ansible-playbook ~/Ansible/setup-anacron.yaml

从此,我就可以编写 shell 脚本来执行一些琐碎但重复的任务,然后把它复制到 ~/.local/etc/cron.daily,让它每天自动运行一次(或者大约如此)。我还为诸如 清理下载文件夹 之类的任务编写了 Ansible 剧本。我把我的剧本放在 ~/Ansible 里,这是我保存 Ansible 剧本的地方,然后在 ~/.local/etc/cron.daily 里创建一个 shell 脚本来执行这个剧本。这很简单,不费吹灰之力,而且很快成为习惯。


via: https://opensource.com/article/21/9/ansible-anacron-automation

作者:Seth Kenlon 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

你将在本篇新手教程中学习如何在 Ubuntu、Debian 及其他 Linux 发行版中安装 Vivaldi 网页浏览器,同时本教程也将介绍如何更新和卸载该软件。

Vivaldi 是一款日益流行的网页浏览器。它基于 Chromium 内核,因此它拥有和 Chrome 类似的功能,但它也新增了一些其他特色功能,让这款浏览器与众不同、更为直观。

它内置了标签组、广告拦截、鼠标手势、笔记管理,甚至还有命令连锁。你甚至可以借助切分视图来一次性浏览多个页面。当然,相比于 Chrome,Vivaldi 更加尊重你的隐私。

标签平铺,一次性分割浏览多个页面

Manjaro Linux 近期使用 Vivaldi 取代 Firefox 作为其部分变体的默认浏览器,你可以从这件事来了解 Vivaldi 浏览器的受欢迎程度。

如果你想尝试一下这款浏览器的话,接下来让我告诉你,如何在 Linux 上安装 Vivaldi。你将了解到:

  • 安装 Vivaldi 的 GUI 和命令行方式
  • 将 Vivaldi 更新到最新版本的技巧
  • 在 Ubuntu 中卸载 Vivaldi 的方式

非自由软件警告!

Vivaldi 并非完全的开源软件。它的 UI 界面是闭源的。之所以在这里介绍这款浏览器,是因为 Vivaldi 团队正努力让该软件在 Linux 平台上可用。

方式 1:在 Ubuntu 中安装 Vivaldi [GUI 方式]

好消息是,Vivaldi 提供了预先构建好的安装包,包括 Ubuntu/Debian 的 DEB 文件,以及 Fedora、Red Hat、SUSE 的 RPM 文件。

它支持 32 位和 64 位平台,也支持 像树莓派之类的 ARM 设备

Vivaldi 为各类 Linux 发行版提供了安装包

安装过程非常简单。你只需要前往 Vivaldi 的官网下载正确的安装包文件,双击打开,然后安装,大功告成。

我将详细介绍在 Ubuntu/Debian 下的安装过程。对于其他类型的发行版,你可以使用类似的步骤。

第 1 步:下载 Vivaldi

前往 Vivaldi 的下载页面,下载支持 Ubuntu 的 DEB 格式安装包。

下载支持 Ubuntu/Debian 的 DEB 安装包

第 2 步:安装刚刚下载的 DEB 文件

前往你刚刚下载 DEB 文件的下载文件夹。安装 DEB 文件 非常简单,只需要双击打开,或者右键后使用软件中心打开即可。

右键点击下载的 DEB 文件并用软件中心打开以安装

这将打开软件中心,在这里可以看到安装 Vivaldi 的选项。点击安装按钮即可。

点击安装按钮

你将需要输入系统账户的密码,输入密码授权后,Vivaldi 很快就能完成安装,随后安装按钮也变成了移除按钮。这表明 Vivaldi 已经安装完成了。

第 3 步:使用 Vivaldi

按下 SuperWindows)键打开系统菜单,搜索 Vivaldi,然后单击 Vivaldi 的图标。

在系统菜单中搜索 Vivaldi

首次启动时,你将看到如下界面。

运行于 Ubuntu 的 Vivaldi

既然你已经知道了这个方法,那我接下来将展示在 Ubuntu/Debian 使用终端安装 Vivaldi 的方法。

方式 2:借助终端,在 Ubuntu/Debian 上安装 Vivaldi

打开终端,确认你已经安装了用于 在命令行下下载文件wget

sudo apt install wget

接下来,获取 Vivaldi 仓库的公钥并添加到系统,以让系统信任该来源的软件包。如果你感兴趣的话,你可以阅读 关于在 Ubuntu 添加第三方软件仓库的文章

wget -qO- https://repo.vivaldi.com/archive/linux_signing_key.pub | sudo apt-key add -

添加完该密钥后,再添加 Vivaldi 的仓库:

sudo add-apt-repository 'deb https://repo.vivaldi.com/archive/deb/ stable main'

现在距离完成也只有一步之遥了。更新软件仓库缓存并安装 Vivaldi。

sudo apt update && sudo apt install vivaldi-stable

大功告成。现在,前往系统菜单搜索并启动 Vivaldi 吧。

在 Ubuntu 中更新 Vivaldi

GUI 和命令行这两种方式都会在系统里添加 Vivaldi 的仓库。这意味着,只要 Vivaldi 发布了新版本,你就可以在系统更新中一并获取 Vivaldi 的更新。

已添加到系统中的 Vivaldi 仓库

一般情况下,你更新 Ubuntu 系统时,如果 Vivaldi 发布了新版本,那么 Vivaldi 也同时会被更新。

Vivaldi 浏览器会跟随系统更新

在 Ubuntu 中卸载 Vivaldi

如果你不喜欢 Vivaldi 或者不再使用,你可以直接卸载。现在,如果你想 在 Ubuntu 中卸载软件,你可能会想到软件中心,但软件中心不会查找到外部和第三方的软件包。

目前你必须使用终端卸载 Vivaldi,即便你是使用 GUI 方式安装的。其实这也很简单,打开终端,输入以下命令:

sudo apt remove vivaldi-stable

sudo在 Ubuntu 中给予你 root 权限。你需要输入当前账户的密码。输入密码时,你可能不会在屏幕上看见输入密码的痕迹。这是正常现象,直接输入密码即可,随后 Vivaldi 将被卸载。

希望这篇关于如何在 Linux 安装 Vivaldi 的教程对你有用。


via: https://itsfoss.com/install-vivaldi-ubuntu-linux/

作者:Abhishek Prakash 选题:lujun9972 译者:imgradeone 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Jekyll 是一个开源的静态网站生成器。你可以使用 Markdown 编写内容,使用 HTML/CSS 来构建和展示,Jekyll 会将其编译为静态的 HTML。

 title=

近年来开始流行静态网站生成器和 JAMStack,而且理由很充分,它们不需要复杂的后端,只需要静态的 HTML、CSS 和 Javascript。没有后端意味着更好的安全性、更低的运营开销和更便宜的托管。双赢!

在本文中,我将讨论 Jekyll。在撰写本文时,我的个人网站使用的是 Jekyll。Jekyll 使用 Ruby 引擎将用 Markdown 编写的文章转换成 HTML。Sass 可以将复杂的 CSS 规则应用到普通文本文件中。Liquid 允许对静态内容进行编程控制。

安装 Jekyll

Jekyll 网站 提供了 Linux、MacOS 和 Windows 安装说明。安装完成之后,快速引导 将会安装一个基础的 Hello-World 项目。

现在在你的浏览器访问 http://localhost:4000,你可以看到你的默认“真棒”博客。

 title=

目录结构

这个默认站点包含以下的文件和文件夹:

  • _posts: 你的博客文章。
  • _site: 最终编译成的静态网站文件。
  • about.markdown: “关于页”的内容。
  • index.markdown: “主页”的内容。
  • 404.html: “404 页”的内容。
  • _config.yml: Jekyll 的全站配置文件。

创建新的博客帖子

创建帖子很简单。你需要做的就是在 _post 目录下使用正确的格式和扩展名创建一个新文件,这样就完成了。

有效的文件名像 2021-08-29-welcome-to-jekyll.markdown 这样。一个博客文件必须包含 Jekyll 所谓的 YAML 卷首块 Front Matter 。它是文件开头的一个包含元数据的特殊部分。如果你查看默认的帖子,你可以看到以下内容:

---
layout: post
title: "Welcome to Jekyll!"
date:  2021-08-29 11:28:12 +0530
categories: jekyll update
---

Jekyll 会使用上面的元数据,你也可以自定义 key: value 键值对。如果你需要一些提示,请查看我的网站的卷首。除了前面的问题,你还可以 使用内置的 Jekyll 变量 来自定义你的网站。

让我们创建一个新的帖子。在 _posts 文件夹下创建 2021-08-29-ayushsharma.markdown。内容如下:

---
layout: post
title:  "Check out ayushsharma.in!"
date:   2021-08-29 12:00:00 +0530
categories: mycategory
---
This is my first post.

# This is a heading.

## This is another heading.

This is a [link](<http://notes.ayushsharma.in>)

This is my category:

如果 jekyll serve 命令仍在运行,刷新页面,你将看到下面的新帖子。

 title=

恭喜你创建了你的第一篇帖子!这个过程看起来很简单,但是你可以通过 Jekyll 做很多事情。使用简单的 Markdown,你可以归档博客、高亮显示代码片段以及分类管理帖子。

草稿

如果你还没准备好发布你的内容,你可以创建一个 _drafts 文件夹。此文件夹中的 Markdown 文件仅通过传递 --drafts-- 参数来呈现。

布局和包含

请注意 _post 文件夹中两篇文章的卷首块,你将在其中看到 layout: post_layout 文件夹中包含所有布局。你不会在源代码中找到它们,因为 Jekyll 默认加载它们。Jekyll 使用的默认源代码在 这里。如果你点击该链接,你可以看到 post 的布局使用了默认(default)布局。默认布局包含的代码 {{ content }} 是注入内容的地方。布局文件还将包含 include 指令。它们从 include 文件夹 加载文件,并使用不同的组件组成页面。

总的来说,这就是布局的工作方式:你在卷首块定义它们并将你的内容注入其中。而包含则提供了页面的其它部分以组成整个页面。这是一种标准的网页设计技术:定义页眉、页脚、旁白和内容元素,然后在其中注入内容。这就是静态站点生成器的真正威力,完全以编程的方式控制,将你的网站组装起来并最终编译成静态的 HTML。

页面

你网站上的所有内容并不都是文章或博客。你需要“关于”页面、“联系”页面、“项目”页面或“作品”页面。这就是“页面”的用武之地。它们的工作方式与“帖子”完全一样,这意味着它们是带有卷首块的 Markdown 文件。但它们不会放到 _posts 目录。它们要么保留在你的项目根目录中,要么保留在它们自己的文件夹中。对于布局和包含,你可以使用与帖子相同的布局或创建新帖子。 Jekyll 非常灵活,你可以随心所欲地发挥你的创意!你的默认博客已经有 index.markdownabout.markdown。请随意自定义它们。

数据文件

数据文件位于 _data 目录中,可以是 .yml.json.csv 等格式的文件。例如,一个 _data/members.yml 文件可能包含:

- name: A
 github: a@a

- name: B
 github: b@b

- name: C
 github: c@c

Jekyll 在网站生成的时候读取这些内容。你可以通过 site.data.members 访问它们。

<ul>
{ % for member in site.data.members % }
 <li>
 <a href="https://github.com">
      { { member.name } } 
 </a>
 </li>
{ % endfor %}
</ul>

永久链接

你的 _config.yml 文件定义了永久链接的格式。你可以使用各种默认变量来组合你自己的自定义永久链接。

构建你最终的网站

命令 jekyll serve 非常适合本地测试。但是一旦你完成了本地测试,你将需要构建要发布的最终工作。命令 jekyll build --source source_dir --destination destination_dir 将你的网站构建到 _site 文件夹中。请注意,此文件夹在每次构建之前都会被清理,所以不要将重要的东西放在那里。生成内容后,你可以将其托管在你的静态托管服务上。

你现在应该对 Jekyll 的功能以及主要部分的功能有一个全面的了解。如果你正在寻找灵感,官方 JAMStack 网站上有一些很棒的例子

 title=

编码快乐。

本文首发于作者个人博客,经授权改编。


via: https://opensource.com/article/21/9/build-website-jekyll

作者:Ayush Sharma 选题:lujun9972 译者:perfiffer 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

系统上运行着诸多进程,通过 jps 命令能够快速有效识别 Java 进程。

 title=

在 Linux 中,有一些用于查看系统上运行进程的命令。进程是指由内核管理的正在进行的事件。每启动一个应用程序时,就会产生一个进程,但也有许多在计算机后台运行的进程,如保持系统时间准确的进程、监听新文件系统的进程、索引化文件的进程等。有一些可以用来监测这些进程的实用程序,比如包含在 procps-ng 包 中的程序,但它们往往都是对各种进程通用的。它们会查看计算机上的所有进程,你可以根据需要过滤结果列表。

在 Linux 中,可以通过 ps 命令查看进程。这是查看当前系统上运行进程最简单的方法。

$ ps
    PID TTY          TIME CMD
   4486 pts/0    00:00:00 bash
  66930 pts/0    00:00:00 ps

你也可以通过 ps 命令,并配合结果输出管道符进行 grep,从而查看系统上运行的 Java 进程,。

$ ps ax |grep java
  67604 pts/1    Sl+    0:18 /usr/lib/jvm/java-11-openjdk-11.0.12.0.7-4.fc34.x86_64/bin/java -D[Standalone] -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/home/alan/wildfly/24.0.1/standalone/log/server.log -Dlogging.configuration=file:/home/alan/wildfly/24.0.1/standalone/configuration/logging.properties -jar /home/alan/wildfly/24.0.1/jboss-modules.jar -mp /home/alan/wildfly/24.0.1/modules org.jboss.as.standalone -Djboss.home.dir=/home/alan/wildfly/24.0.1 -Djboss.server.base.dir=/home/alan/wildfly/24.0.1/standalone

然而,OpenJDK 有自己专属的进程监视器。 Java 虚拟机进程状态 Java Virtual Machine Process Status (jps)工具可以帮你扫描系统上所有运行的 Java 虚拟机(JVM)实例。

要想实现与 ps 命令类似的输出,可以使用 -v 选项。这很实用,这与 ps 相比,可以减少你的输入。

$ jps -v
67604 jboss-modules.jar -D[Standalone] -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/home/alan/wildfly/24.0.1/standalone/log/server.log -Dlogging.configuration=file:/home/alan/wildfly/24.0.1/standalone/configuration/logging.properties

jps 命令的默认输出包含进程标识符,类名或 Jar 文件名。

$ jps
67604 jboss-modules.jar
69430 Jps

注意: jps 的手册页指出此命令是试验性且不受支持的。尽管如此,它仍然是一个不错的选择,因为一个系统通常运行着许多进程,这种只识别 Java 进程的快速方法是很有用的。

当下的 Java 仍然是一种流行的语言,所以熟悉 Java 开发工具包和运行时环境仍然很重要。它们包含着许多适用于 Java 应用程序开发和维护的工具。


via: https://opensource.com/article/21/10/check-java-jps

作者:Alan Formy-Duval 选题:lujun9972 译者:unigeorge 校对:turbokernel

本文由 LCTT 原创编译,Linux中国 荣誉推出

手动安装可以让用户更好的控制 Java 运行时环境。

 title=

使用 Linux 发行版的软件包管理工具来安装 Java 软件包 是很容易的。然而,有时你需要手动安装 Java。这对基于 Java 的应用服务器(如 Tomcat 或 JBoss)的管理员特别重要。许多开源和专有软件产品都依赖于这些服务。

开发者或运行时套件?

Java 虚拟机 Java Virtual Machine (JVM)以两种不同的形式提供: Java 开发工具包 Java Development Kit (JDK)或 Java 运行时环境 Java Runtime Environment (JRE)。

软件开发人员通常需要 JDK。它包含编译、运行和测试源代码所需的二进制文件。部署一个预先建立的 Java 应用程序通常只需要 JRE。它不包括编译器和其他开发工具。由于安全性的提高和空间的限制,通常在生产环境中安装 JRE。

获取 Java

你可以从网上下载开源的 Java 软件。你可以在 Red Hat DeveloperAdoptium.net 下载 OpenJDK 打包文件,或从 Azul 下载 Zulu 社区版

安装 Java

设置一个目录来存放 Java 文件。我喜欢创建一个简单的名为 java 的目录,这样我就可以在一个专门的目录中下载并解压打包文件:

$ mkdir -p java/jdk

让我们在这个例子中使用 JDK。将下载的文件保存到 jdk 目录下。然后换到该目录:

$ cd java/jdk
$ ls
OpenJDK11U-jdk_x64_linux_hotspot_11.0.12_7.tar.gz

提取该打包文件。注意,tar 会创建一个新的目录:

$ tar xvzf OpenJDK11U-jdk_x64_linux_hotspot_11.0.12_7.tar.gz
$ ls
jdk-11.0.12+7 OpenJDK11U-jdk_x64_linux_hotspot_11.0.12_7.tar.gz

使用 -version 选项确认新 JVM 的版本。

$ cd jdk-11.0.12+7/bin
$ ./java -version

JVM 的版本输出看起来类似这样:

openjdk version "11.0.12" 2021-07-20
OpenJDK Runtime Environment Temurin-11.0.12+7 (build 11.0.12+7)
OpenJDK 64-Bit Server VM Temurin-11.0.12+7 (build 11.0.12+7, mixed mode)

环境变量

为了确保一个特定的应用程序能够正常工作,它需要确切地知道如何定位 JVM。有两个主要的变量需要设置:JAVA_HOMEPATH

$ echo $JAVA_HOME
$ echo $PATH

这些可以在用户的 .bashrc 文件中设置。确保这些变量出现在 任何设置 PATH 的现有代码 之后:

#Set the JAVA_HOME
export JAVA_HOME=~/java/jdk/jdk-11.0.12+7
#Add the JAVA_HOME to the PATH
export PATH="$JAVA_HOME/bin:$PATH"

手动安装的情况

有几种情况需要手动安装 Java。请考虑以下三种情况:

一种情况可能是要求使用不同的,也许是较早的,在你的 Linux 发行版的软件库中已经没有的 Java 版本。

另一个例子可能是由安全推动的决定,即 Java 不会被默认安装在操作系统上或在“根级别”上。

第三种情况是可能需要几个不同版本的 Java,通常是因为 J2EE Web 应用程序的多个实例在同一台服务器上运行。由于越来越多地使用虚拟机和容器来隔离进程,这种操作系统共享在今天已经不太常见了。然而,由于需要维护不同的容器镜像,对手动安装的理解仍然至关重要。

总结

我演示了我手动安装 Java 运行时环境的方式,但你可以制定一个最适合你需求的惯例。最终,手动安装让用户可以更好的控制 Java 运行时环境。


via: https://opensource.com/article/21/9/install-java-manually-linux

作者:Alan Formy-Duval 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出