L B T

记 录 过 去 的 经 验

Linux X Window System

早期的 Linux 桌面都是基于来自 X.Org Foundation(http://www.x.org) 的 X Window System 的接口。一个 X.Org 的替代者是 Wayland (http://wayland.freedesktop.org)。

X Window System(简称 X)在 Linux 之前就存在,甚至早于 Microsoft Windows,它是一个轻量的、基于网络的桌面框架。

X Window System 是一种 Client/Server 模型。X Server 运行于本地操作系统中,为屏幕(Screen)、鼠标(Mouse)、键盘(Keyboard)提供对外的接口,X Client 可以在本地或者任何基于网络的远端系统上面运行。

X Server 本身只提供了一个简单的灰色背景和一个 X 型鼠标光标,没有菜单、面板、图标等,如果只是单纯的启动 X Client 展示 X Server 的内容,它展示的内容中不会包含 可以移动的边框、最大化、最小化按钮以及关闭窗口的按钮等 ,这些特性是由 Window Manager 提供的。

Window Manager 添加了可以操作程序的很多特性,如菜单、边框、常用按钮等。

Linux 中常见的桌面环境包括:

  • GNOME : 最初是为了模仿 MacOS 桌面
    • Gnome 2
    • Gnome 3 : 完全和 Gnome 2 的设计思路和理念不同,是一个全新的版本
  • K Desktop Environment (KDE) : 模拟了 Microsoft Windows 桌面
  • Xfce : 第一个轻量版的桌面环境,可以在系统资源(CPU,Mem)较少的环境中运行
  • LXDE : The Lightweight X11 Desktop Environment. 是一个高性能、节能的桌面环境。

Gnome3 相关常用操作

Gnome 3 提供了很多可用的插件来满足不同的需求,并提供了工具 Gnome Tweaks 用于调整 Gnome 的配置

Gnome Shell Extensions 可以控制 Gnome 桌面的外形和行为方式。GNOME Shell Extensions site (http://extensions.gnome.org)

查看 Gnome 版本

方法 1:通过设置查看

  1. 打开 “设置”:

    点击屏幕左下角的 “显示应用程序” 按钮(或按 Super 键,也就是通常的 Windows 键)。
    输入 Settings设置,然后点击出现的应用图标。
    查看 “关于” 信息:

  2. 在左侧面板中,向下滚动并选择 “关于”(About)。
    在“关于”页面中,你会看到 GNOME 版本信息以及其他系统详细信息。

方法 2:通过终端查看

你也可以通过终端命令查看 GNOME 版本:

  1. 打开终端:

    Ctrl + Alt + T 打开终端。

  2. 使用以下命令

    $ gnome-shell --version
    GNOME Shell 42.9

隐藏 Gnome 桌面顶部的工具栏

版本信息

  • Ubuntu 22.04.4 LTS (Jammy Jellyfish)
  • Gnome Shell 42.9

参考以下步骤:

  1. 安装 gnome-shell-extension-manager
    sudo apt-get install gnome-shell-extension-manager

  2. 打开 Extension-Manager
  3. 点击 Browse,搜索 hidetopbar 这个插件并安装(注意选择 Downloads!!,要不然搜不到插件

安装好了 hidetopbar 这个插件之后,上方的任务栏/状态栏 在窗口全屏时就会自动隐藏Super 键或者窗口非全屏时会重新显示

阅读全文 »

环境信息

  • Python 3.11.2

安装

pip install requests

常见用法

get 请求

get 请求及响应中常用的属性

>>> r = requests.get('https://csms.tech')
>>> dir(r)
[..., 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history',
'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines',
'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason',
'request', 'status_code', 'text', 'url']

带参数的 get 请求

要在 get 请求中携带请求参数,可以使用以下方法

>>> help(requests.get)
get(url, params=None, **kwargs)
Sends a GET request.

:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary, list of tuples or bytes to send
in the query string for the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response

>>> params = {'k1': 'v1', 'k2': 'v2'}
>>> r = requests.get('https://csms.tech', params=params)

# 设置请求头
>>> headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
>>> response = requests.get("https://csms.tech", params = params, headers = headers)

get 方法本质上是通过创建了一个 requests.Request 对象,因此 **kwargs 可用的值可以通过查看 requests.Request 的帮助信息。

>>> help(requests.Request)
阅读全文 »

环境信息

  • Selenium > 4.0

Selenium 是一个用于自动化 Web 浏览器操作的工具,可以用于模拟用户与网站的交互。

使用 pip 安装 Selenium 库

pip install selenium

Selenium 需要一个 WebDriver 来控制不同的浏览器。可以根据要使用的浏览器下载相应的 WebDriver。以下是一些常见的浏览器和对应的WebDriver下载链接:

下载 WebDriver 并确保它在系统路径中可用。WebDriver 和浏览器具有版本对应关系,要确保版本匹配

selenium 常见用法总结

本示例中以 Chrome 浏览器为例。

  • 创建一个浏览器实例,并请求指定的页面

    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Chrome()

    driver.get("https://www.example.com")
  • 关闭当前浏览器窗口

    driver.close()
  • 最大化浏览器窗口

    driver.maximize_window()
  • 后退

    driver.back()
  • 前进

    driver.forward()
  • 刷新页面

    driver.refresh()
  • 关闭浏览器

    driver.quit()
    阅读全文 »

2Captcha 是一个验证码自动识别服务商。

验证码可以是含有必填扭曲文字的图片,也可以由不同图片组成,用户需从中选出符合特定条件的图片。这些操作是为了证明用户不是机器人。

环境信息

  • Python 3
  • 2captcha-python v1.2.8 [1]

2captcha 安装配置

2captcha 安装

参考官网安装文档 安装 Python3 模块

pip3 install 2captcha-python

使用简介

调用 2captcha 需要注册并使用 2captcha 提供的 API 密钥。

以下代码示例返回滑块类型的验证结果:


from twocaptcha import TwoCaptcha

# Initialize 2Captcha solver
config = {
'server': '2captcha.com',
'apiKey': 'ef5beb9c280ce7452183',
'defaultTimeout': 120,
'recaptchaTimeout': 600,
'pollingInterval': 10,
}

solver = TwoCaptcha(**config)

result = solver.coordinates(
'background_img.png',
hintImg='slider_img.png',
hintText="向右滑动填充拼图",
)
print(f'Captcha solved: {result}')

存在的问题

按照以上代码示例,针对相同的图片,每次请求返回的结果都不一样。2Captcha 针对滑块验证成功率太低,基本不可用。

Captcha solved: {'captchaId': '77043576230', 'code': 'coordinates:x=286,y=41'}

Captcha solved: {'captchaId': '77043579057', 'code': 'coordinates:x=276,y=45'}

Captcha solved: {'captchaId': '77043582438', 'code': 'coordinates:x=281,y=55'}

要缓解此问题,可以使用 2Captcha 提供的 100% 识别服务,原理是通过将验证码发送给多个员工进行匹配,满足配置的条件才返回结果(根据官方回复,100% 识别服务只能针对 normal captchas 完全生效,对滑块类型的验证基本不可能得到相同的结果相关链接

参考链接|Bibliography

2Captcha 在线破解验证码

脚注

Memory

内存管理相关的系统关键进程

Name Path Info Demonstrate
[kswapd0] 由内核启动 Linux 内核中的一个内存管理守护进程,负责内存交换(swap).当系统内存不足时,触发内存回收机制,释放不常用的内存页。
内存回收使用 Page Replacement 算法(新版本使用)
kswapd
阅读全文 »

环境信息

  • Centos 7

查看内核已加载的模块

使用 lsmod 命令列出所有已加载的内核模块,输出中包含: 模块名称(Name)大小(Size)何处被使用(Used by)

# lsmod 
Module Size Used by
softdog 12288 0
xt_MASQUERADE 16384 2
nf_conntrack_netlink 53248 0
nfnetlink 20480 2 nf_conntrack_netlink
iptable_nat 12288 1
nf_nat 57344 2 iptable_nat,xt_MASQUERADE
xt_addrtype 12288 2
br_netfilter 32768 0
overlay 180224 0
ipt_REJECT 12288 2
nf_reject_ipv4 16384 1 ipt_REJECT
xt_comment 12288 7
xt_multiport 16384 2
xt_conntrack 12288 10
nf_conntrack 188416 4 xt_conntrack,nf_nat,nf_conntrack_netlink,xt_MASQUERADE
nf_defrag_ipv6 24576 1 nf_conntrack
nf_defrag_ipv4 12288 1 nf_conntrack

查看内核模块的详细信息

要查看已加载的内核模块的详细信息,可以使用 modinfo 命令,不是所有的模块都有详细的描述信息,如果没有,则无任何返回

# modinfo -d ena
Elastic Network Adapter (ENA)

# modinfo -d lp

# modinfo -n ena
/lib/modules/6.8.0-1015-aws/kernel/drivers/net/ethernet/amazon/ena/ena.ko

modinfo 命令常用选项:

选项 说明 示例
-a, --author 打印模块的作者
-d, --description 打印模块的描述信息
-p, --parameters 打印模块的 ‘parm’
-n, --filename Print only ‘filename’

加载内核模块

insmod

使用 insmod 命令加载内核模块. 模块需要完整后缀(如果有)

insmod simple.ko

modprobe

使用 modprobe 命令加载内核模块. 模块不需要完整后缀(如果有) 。临时加载,重启后会消失。

# modprobe parport

卸载内核模块

使用 rmmod 命令卸载内核模块。无需后缀,只需要给定模块名

rmmod simple

也可以使用命令 modprobe -r 移除模块,它不仅会移除指定的模块,还会移除未被继续使用的依赖的模块

环境信息

  • Centos 7

常用目录和文件说明

etc 目录常用文件说明

文件路径 说明 示例
/etc/motd 登录成功后的欢迎信息,ssh 登录和 console 登录成功后都会显示
/etc/issue 在登录系统输入用户名之前显示的信息,远程 ssh 连接的时候并不会显示此信息 说明示例
/etc/services 记录网络服务名和它们对应使用的端口号及协议
/etc/protocols 该文件是网络协议定义文件,里面记录了 TCP/IP 协议族的所有协议类型。文件中的每一行对应一个协议类型,它有3个字段,分别表示 协议名称协议号协议别名
/etc/vimrc
~/.vimrc
vim 启动时会读取 /etc/vimrc(全局配置) 和 ~/.vimrc (用户配置) vim
/etc/passwd
/etc/shadow
/etc/group
用户数据库,其中记录了 用户名id用户家目录shell
用户密码文件
组信息
/etc/fstab 系统启动时需要自动挂载的文件系统列表
/etc/mtab 当前系统已挂载的文件系统,并由 mount 命令自动更新。当需要当前挂载的文件系统的列表时使用(例如df命令)
/etc/shells 系统可使用的 shell
/etc/filesystems 系统可使用的 文件系统
/etc/hostname 存放这主机名
/etc/hosts 主机名查询静态表,域名和 ip 本地静态表
/etc/nsswitch.conf 它规定通过哪些途径以及按照什么顺序以及通过这些途径来查找特定类型的信息,还可以指定某个方法奏效或失效时系统将采取什么动作 hosts: files dns myhostname
此配置设定:在查找域名解析的时候,先查找本地 /etc/hosts,再发送给 DNS 服务器查询
/etc/rsyslog.conf rsyslog 服务的配置文件,用来托管其他服务的日志 linux rsyslog 服务
/etc/logrotate.conf linux 日志切割工具 linux logrotate 服务
/etc/rsyncd.conf rsync 服务的配置文件 rsyncd 服务
/etc/sysctl.conf
/etc/sysctl.d/
内核的运行参数配置文件,sysctl 命令对内核参数的修改仅在当前生效,重启系统后参数丢失,如果希望参数永久生效可以修改此配置文件 Linux 常用内核参数说明
阅读全文 »

在 Python 中,set 是一种无序的、可变的集合数据类型,用于存储唯一的元素。它主要用于快速去重和集合运算(如交集、并集、差集等)。

环境信息

  • Python 3

set 基本操作

创建集合

可以使用花括号 {}set() 函数来创建集合。

  • 使用花括号创建集合

    # 创建一个包含一些元素的集合
    my_set = {1, 2, 3, 4, 5}
    print(my_set) # 输出: {1, 2, 3, 4, 5}
  • 使用 set() 函数创建集合

    # 使用 set() 函数从一个可迭代对象创建集合
    my_set = set([1, 2, 3, 4, 5])
    print(my_set) # 输出: {1, 2, 3, 4, 5}

    # 创建一个空集合
    empty_set = set()
    print(empty_set) # 输出: set()

集合的基本操作

添加元素

使用 add() 方法向集合添加单个元素。

my_set = {1, 2, 3}
my_set.add(4)
print(my_set) # 输出: {1, 2, 3, 4}

移除元素

使用 remove() 方法移除集合中的指定元素,如果元素不存在会引发 KeyError。使用 discard() 方法移除元素,如果元素不存在不会引发异常。

my_set = {1, 2, 3}
my_set.remove(2)
print(my_set) # 输出: {1, 3}

my_set.discard(3)
print(my_set) # 输出: {1}

# remove 不存在的元素会引发 KeyError
# my_set.remove(4) # KeyError: 4

# discard 不存在的元素不会引发异常
my_set.discard(4)
print(my_set) # 输出: {1}

清空集合

使用 clear() 方法清空集合中的所有元素。

my_set = {1, 2, 3}
my_set.clear()
print(my_set) # 输出: set()

集合的长度

使用 len() 函数获取集合中元素的个数。

my_set = {1, 2, 3}
print(len(my_set)) # 输出: 3

集合运算

并集

使用 | 运算符或 union() 方法。

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 使用 | 运算符
print(set1 | set2) # 输出: {1, 2, 3, 4, 5}

# 使用 union() 方法
print(set1.union(set2)) # 输出: {1, 2, 3, 4, 5}

阅读全文 »

环境信息

  • Python3

字符串转换为变量名

locals() 方法

>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>> locals()[a]
666

vars() 方法


>>>
>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>>
>>> vars()[a]
666
>>>

eval() 方法

>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>> eval(a)
666

yield

yield 指令和 return 相似,都是用来在函数中返回。使用 yield 关键字创建生成器函数时,生成器函数并不会在传统意义上 返回。相反,生成器函数在遇到 yield 语句时会暂停其执行,并返回一个值给调用者。生成器函数的状态会被保存,因此在下一次调用时,它可以从暂停的地方继续执行。

yield 指令 将函数转换成生成器(Generator,它在函数中产生一个值,然后暂停函数并保存其状态(下一次调用函数会从此状态恢复执行),再次恢复执行时再生成(返回)yield 的值。

每次调用生成器函数时,并不会立即执行,会创建一个新的生成器对象。

第一次使用 next() 或在 for 循环中开始迭代生成器时,生成器函数开始执行,直到遇到第一个 yield 语句。yield 会暂停生成器函数的执行,并将一个值返回给调用者。再次调用 next() 或继续迭代(for)时,生成器函数从上次暂停的 yield 处继续执行,直到遇到下一个 yield 语句或执行结束。

生成器函数在没有 yield 语句时结束执行,相当于隐式地在最后一个 yield 语句之后遇到 return

当生成器函数结束时,进一步调用 next() 会引发 StopIteration 异常,表示生成器中的值已被全部生成。

yield 有以下优点:

  • 能够以更高效的方式处理大量数据,因为它不需要一次性将所有数据存储在内存中。通过减少内存消耗,提高程序性能。
  • 它提供了一种新的方法来控制函数的执行流程,使得函数可以在任意点暂停和恢复。生成器函数在被暂停后(遇到 yield)不会继续执行,直到再次调用 next() 或通过迭代器进行迭代(for)。

yield 读取大文本数据

在处理大文本数据(如超过 10G)时,如果一次性读取所有文本内容,在可用内存较小的情况下可能出现内存不足导致程序执行失败。这时候可以考虑使用 yield 来批量加载数据。

定义如下函数读取文件内容:

def read_large_file(file_path):
"""
Generator function to read a large file line by line.
"""
with open(file_path, 'r') as file:
for line in file:
yield line

使用以下方法使用大文本中的数据

  1. next 方法。调用生成器函数(read_large_file),会返回一个 Generator 对象,通过 next() 方法会迭代调用生成器的下一个值(yield 表达式的值)
    file_path = 'large_file.txt'

    # next 方法: 首先
    line = read_large_file(file_path)

    next(line) # 返回第一行
    next(line) # 返回第二行,以此类推可以读取所有行

  2. for 循环。调用生成器函数返回一个生成器对象,这个对象实现了迭代器协议。
    def read_large_file(file_path):
    """
    Generator function to read a large file line by line.
    """
    with open(file_path, 'r') as file:
    for line in file:
    yield line

    # Usage example
    file_path = 'large_file.txt'
    for line in read_large_file(file_path):
    print(line.strip())

分批读取大文件中的数据

在处理大文件的过程中,如果需要批量多行读取文件内容,参考以下代码

def read_file_in_chunks(file_path, chunk_size=1024):
"""
Generator function to read a file in chunks.
"""
with open(file_path, 'r') as file:
while True:
chunk = file.readlines(chunk_size)
if not chunk:
break
for line in chunk:
yield line

# Usage example
file_path = 'large_file.txt'
for line in read_file_in_chunks(file_path):
print(line.strip())

enumerate

enumerate 是 Python 内置函数之一,用于遍历可迭代对象(如列表、元组或字符串)时获取元素和对应的索引。

语法:

enumerate(iterable, start=0)
  • iterable : 任何可迭代对象(如列表、字符串、元组、文件对象等)。
  • start : 索引的起始值,默认为 0。如果要让索引号从 1 开始,配置 start=1
# 示例列表
>>> fruits = ['apple', 'banana', 'cherry']

# 使用 enumerate 获取元素及其索引
>>> for index, fruit in enumerate(fruits):
... print(index, fruit)
...
0 apple
1 banana
2 cherry
>>>


# 使用 enumerate 获取元素及其索引,并将起始索引改为 1
>>> for index, fruit in enumerate(fruits, start=1):
... print(index, fruit)
...
1 apple
2 banana
3 cherry

# 使用 enumerate 获取文件中的行号及其内容
>>> f = open('temp_file')
>>> for line_number, line in enumerate(f):
... print(line_number, line)
...
0 85d37fac5cc284914b5d6f79982942b8/Y1iY3k1U.ts

1 85d37fac5cc284914b5d6f79982942b8/Y1x0V8Rc.ts

2 85d37fac5cc284914b5d6f79982942b8/Y22fhGiC.ts

3 85d37fac5cc284914b5d6f79982942b8/Y3p95oau.ts

常见错误

NameError: name ‘null‘ is not defined

使用 evalstring 转化成 dict 时出错,经过排查,发现 string 数据中包含 null,在转换时就会报错: NameError: name ‘null‘ is not defined

解决方法

使用 json 进行转换

try:
response_dict = eval(response)
except NameError:
response_dict = json.loads(str(response.decode()))

  • 蛙化及蛇化

  • 蛙化現象 是日本 2023 年上半年的 Z 世代(出生介於1995年~2010年)流行用語第一名。這個詞源自格林童話《青蛙王子》,描述對另一半突然感到生理或心理上厭惡。

    日本大學教授藤澤伸介在2004年的研究指出,「蛙化現象」是一種普遍狀態,尤其容易發生在情竇初開的青少年身上,因為戀愛經驗少,對感情對象抱持完美的想像。

與蛙化現象相對,近期有對情侶在TikTok發明「蛇化現象」,描述無論另一半做了什麼尷尬行為,都感到好可愛。這種現象迅速散播,成為日本Z世代流行用語。

  • 于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡

  • 你永远不可能真正去了解一个人,除非你穿过她的鞋子去走她走过的路,站在她的角度思考问题,可当你走过她走的路时,你连路过都觉得难过。

  • 当一个人因为和你无关的事情而生气并向你抱怨和展示自己的生气和愤怒时,你最好不要对涉及到的人或事发表任何意见,千万不要对涉及到的人或事发表任何意见千万不要对涉及到的人或事发表任何意见,你最好 当个听客,闭紧嘴巴,不然很可能引火烧身。

  • 当你只能孤注一掷的时候,你只能孤注一掷。如果你犹豫不决,说明你其实还有办法,只是不愿意使用。

  • 对一个人好是一件太过笼统的说法,没法测量,如需测量,可以将这个说法进行分解,比如分解为:
    对一个人好 = 能为他着想 + 站在他的角度考虑

状态标识 状态名称 状态说明 示例
R task_running 进程处于运行或就绪状态
S task_interruptible
sleeping
可中断的睡眠状态
D task_uninterruptible 不可中断的睡眠状态
1. 它是一种睡眠状态,意味着处于此状态的进程不会消耗 CPU
2. 睡眠的原因是等待某些资源(比如锁或者磁盘 IO),这也是非常多 D 状态的进程都处在处理 IO 操作的原因
3. 是它不能被中断,这个要区别于 硬件中断 的中断,是指不希望在其获取到资源或者超时前被终止。因此他不会被信号唤醒,也就不会响应 kill -9 这类信号。这也是它跟 S(可中断睡眠)状态的区别
T task_stopped
task_traced
Traced
暂停状态或跟踪状态
Z task_dead
exit_zombie
zombie
退出状态,进程成为僵尸进程
X task_dead
exit_dead
退出状态,进程即将被销毁
I idle 空闲状态

进程命令名和进程可执行文件名

在系统中遇到以下进程:

# ps -elf | grep 18686
5 S root 18686 1239 0 80 0 - 46620 pipe_w 15:50 ? 00:00:00 /usr/sbin/CROND -n
0 R root 18694 18686 7 80 0 - 610547 - 15:50 ? 00:00:02 /usr/local/php73/bin/php /home/www/admin/artisan PullData
0 S root 18754 18686 0 80 0 - 22453 pipe_w 15:50 ? 00:00:00 /usr/sbin/sendmail -FCronDaemon -i -odi -oem -oi -t -f root

其中 PID 为 18686 的进程名为 /usr/sbin/CROND,其启动了另外两个子进程。但是在系统中检查,并不存在路径 /usr/sbin/CROND

# ls -l /usr/sbin/CROND
ls: cannot access /usr/sbin/CROND: No such file or directory

出现此种现象,主要是因为 在启动时,进程的命令名是根据路径传递给 execve() 函数的参数决定的,而不是直接与系统中的文件进行匹配

在 Linux 系统中,ps 命令显示的进程信息是从 /proc 文件系统中获取的,而 /proc 文件系统包含有关正在运行的进程的信息,包括每个进程的命令名。因此,即使实际上系统中不存在 /usr/sbin/CROND 文件,但如果进程的命令名是 /usr/sbin/CROND,那么 ps 命令仍然会显示进程的命令名为 /usr/sbin/CROND

进程的命令名可以查看 /proc/<PID>/cmdline 文件,本示例中显示如下:

# cat /proc/18686/cmdline 
/usr/sbin/CROND-n

对应的系统上的可执行文件的名称可以查看 /proc/<PID>/stat/proc/<PID>/comm/proc/<PID>/status 等文件

# cat /proc/900/comm 
crond

# cat /proc/900/status
Name: crond
Umask: 0022
State: S (sleeping)
Tgid: 900
Ngid: 0
Pid: 900
PPid: 1239
TracerPid: 0

# cat /proc/900/stat
900 (crond) S 1239 1239 1239 0 -1 4202816 1627 0 0 0 0 0 0 0 20 0 1 0 139129633 190955520 1478 18446744073709551615 94685936058368 94685936118156 140733000396032 140733000262488 140427856103840 0 0 4096 16387 18446744071797306256 0 0 17 3 0 0 0 0 0 94685938219080 94685938221648 94685948321792 140733000400770 140733000400789 140733000400789 140733000400872 0

在本示例中,实际执行的命令为 crond

进程状态查看

top 命令

使用 top 命令可以查看系统负载、CPU 和 内存使用情况。也可以查看单个进程的具体信息。

top 命令常用选项

选项 说明 示例
-H Threads Mode,线程模式。默认情况 top 展示进程的简要信息,使用此选项显示进程中的线程状态。
对应交互式命令 H
  • 显示单个进程的(线程)详细信息
    # top -H -p 1423
    top - 09:44:42 up 54 days, 23:53, 2 users, load average: 8.82, 6.84, 7.21
    Threads: 15 total, 0 running, 15 sleeping, 0 stopped, 0 zombie
    %Cpu(s): 40.9 us, 10.8 sy, 0.0 ni, 48.1 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
    KiB Mem : 15790488 total, 466056 free, 7761544 used, 7562888 buff/cache
    KiB Swap: 0 total, 0 free, 0 used. 3895716 avail Mem

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
    1423 root 20 0 1477368 778788 4260 S 39.5 4.9 11999:41 [watchdog:1:6]
    2572 root 20 0 1477368 778788 4260 S 37.9 4.9 11363:48 [watchdog:1:6]
    1436 root 20 0 1477368 778788 4260 S 34.2 4.9 11286:08 [watchdog:1:6]
    1435 root 20 0 1477368 778788 4260 S 33.9 4.9 12059:53 [watchdog:1:6]
    1434 root 20 0 1477368 778788 4260 S 33.2 4.9 10249:00 [watchdog:1:6]
    1437 root 20 0 1477368 778788 4260 S 30.6 4.9 11717:47 [watchdog:1:6]
    1431 root 20 0 1477368 778788 4260 S 28.9 4.9 11222:06 [watchdog:1:6]
    21378 root 20 0 1477368 778788 4260 S 27.6 4.9 12143:35 [watchdog:1:6]
    1433 root 20 0 1477368 778788 4260 S 17.6 4.9 8738:21 [watchdog:1:6]
    1428 root 20 0 1477368 778788 4260 S 8.0 4.9 7650:56 [watchdog:1:6]
    1429 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.04 [watchdog:1:6]
    1430 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.05 [watchdog:1:6]
    1432 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.03 [watchdog:1:6]
    1438 root 20 0 1477368 778788 4260 S 0.0 4.9 12260:30 [watchdog:1:6]
    1529 root 20 0 1477368 778788 4260 S 0.0 4.9 11068:39 [watchdog:1:6]

参考文档

Linux进程状态说明

环境信息

  • ansible-core 2.16
  • Docker image python:3.12.3
Ansible 安装部署参考 Ansible playbook 使用介绍

Ansible 使用 Jinja2 模板语言对变量或者 Facts 进行模板化。 [1]

模板数据处理

Filters

使用 Filters 可以进行数据转换(如 JSON –> YAML)、URL 分割等操作。 [2]

为变量提供默认值

在模板中使用的变量未定义的情况下,可能会导致 Ansible 处理失败,为了以更优雅的方式处理此类问题,可以在模板中为变量提供 默认值

{{ some_variable | default(5) }}

也可以在变量计算值为空或者 false 时使用默认值

{{ lookup('env', 'MY_USER') | default('admin', true) }}

配置变量为可选变量

默认情况下,Ansible Template 中所有的变量都必须有值,否则会抛出异常。假如需要在模板中的部分变量没有值或未定义的情况下也可以正常部署,可以将其配置为 可选(optional)

要将变量配置为 **可选(optional)**,可以将其 默认值(default value) 设置为特殊变量 omit

- name: Touch files with an optional mode
ansible.builtin.file:
dest: "{{ item.path }}"
state: touch
mode: "{{ item.mode | default(omit) }}"
loop:
- path: /tmp/foo
- path: /tmp/bar
- path: /tmp/baz
mode: "0444"

变量类型

如果需要对变量类型进行转换,可以参考以下方法

获取变量类型

2.3 以上版本中,可以使用 type_debug 显示变量类型

{{ myvar | type_debug }}

字典转换为列表

New in version 2.6.

{{ dict | dict2items }}

原始字典数据:

tags:
Application: payment
Environment: dev

使用 {{ dict | dict2items }} 转换后的列表数据:

- key: Application
value: payment
- key: Environment
value: dev

转换后的列表默认以关键字 key 指示之前的字典中的 key 值,以关键字 value 指示之前的字典中的 value 值。如果想要自定义 key 名称,dict2items 接受关键字参数 key_namevalue_name

# Dictionary data (before applying the ansible.builtin.dict2items filter):
files:
users: /etc/passwd
groups: /etc/group

# applying the ansible.builtin.dict2items filter
{{ files | dict2items(key_name='file', value_name='path') }}

# List data (after applying the ansible.builtin.dict2items filter):
- file: users
path: /etc/passwd
- file: groups
path: /etc/group

列表转换为字典

{{ tags | items2dict }}

List data (before applying the ansible.builtin.items2dict filter):

tags:
- key: Application
value: payment
- key: Environment
value: dev

Dictionary data (after applying the ansible.builtin.items2dict filter):

Application: payment
Environment: dev

假如 List Data 中的关键字不是 keyvalue,此时必须使用参数 key_namevalue_name 指定

{{ fruits | items2dict(key_name='fruit', value_name='color') }}

强制类型转换

使用以下语法强制转换变量数据类型 [5]

some_string_value | bool

ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release'] | int

YAML 和 JSON 数据转换

可以使用以下语法将数据转换为 JSON 或者 YAML 格式

{{ some_variable | to_json }}
{{ some_variable | to_yaml }}

可以使用以下语法将数据转换为方便人类阅读 JSON 或者 YAML 格式

{{ some_variable | to_nice_json }}
{{ some_variable | to_nice_yaml }}

制定行首缩进程度

{{ some_variable | to_nice_json(indent=2) }}
{{ some_variable | to_nice_yaml(indent=8) }}

参考链接

Templating (Jinja2)

脚注

环境信息

  • ansible-core 2.16
  • Docker image python:3.12.3
Ansible 安装部署参考 Ansible templates 使用介绍

Ansible Playbook 语法

Playbooks 使用 YAML 语法定义(描述)。一个 playbook 由一个或多个 play 依序组成。每个 play 运行一个或多个 tasks,每个 task 也成为一个 module

Ansible playbook 示例:

playbook.yml
---
- name: Update web servers
hosts: webservers
remote_user: root

tasks:
- name: Ensure apache is at the latest version
ansible.builtin.yum:
name: httpd
state: latest

- name: Write the apache config file
ansible.builtin.template:
src: /srv/httpd.j2
dest: /etc/httpd.conf

- name: Update db servers
hosts: databases
remote_user: root
vars:
port: 8080

tasks:
- name: Ensure postgresql is at the latest version
ansible.builtin.yum:
name: postgresql
state: latest

- name: Ensure that postgresql is started
ansible.builtin.service:
name: postgresql
state: started

---
- name: Install multiple packages
hosts: webservers
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- curl

一个 Ansible playbook 由一个或多个 plays 组成,每个 play 包含以下部分:

  • name : 描述性的名称
  • hosts : 指定目标主机
  • become : 提升权限(默认是使用 sudo 提升到 root 用户)
  • remote_user : 用于连接到远程主机的账户。(如果 Inventory 中定义了远程连接的用户,会覆盖此处的配置)
  • tasks : 要执行的一系列任务列表
  • vars : 用于定义变量,便于管理和重用
  • gather_facts : 收集 Facts, 默认值为 yes

tasks 是一个任务列表,每个任务执行特定的操作。任务包含以下元素:

  • name : 描述任务的目的。
  • module_name : Ansible 模块名称,如 aptservice 等。
  • module_options : 模块的参数,以键值对的形式提供。
  • when : 条件语句,控制任务是否执行。
  • loop : 循环执行任务

执行以下命令运行 playbook.yml

ansible-playbook playbook.yml -f 10

常用选项说明

选项 说明 示例
-f
--forks
指定并发执行的数量,默认为 5
-v
--verbose
-vvvvvv
打印 debug 信息,详细程度从 -v-vvvvvv
-C
--check
Check mode,不执行任何实际操作,而是对要执行的操作进行验证
-D
--diff
- 只使用 --diff 会执行 play 定义的实际操作,并对所有受影响的文件或者模板显示其变更前后的具体差异
- --check 一起使用,不会执行 play 定义的实际操作,只显示变更前后的差异,可以在实际执行前,调试/预览将要进行的变更,防止意外配置变更或文件修改
主要用于文件或者模板的变更,对于其他类型的任务(如包安装、服务管理、修改主机名等),不会显示具体的差异( 配合 --check 使用时,结果会显示为 skipping,实际执行时结果为 changed )。
--list-hosts 不执行任何实际操作,只列出符合 pattern 的目标主机
--list-tasks 不执行任何实际操作,只列出将要执行的 task
--syntax-check 不执行任何实际操作,只检查 playbook 文件是否有语法错误

when 语句

在 Ansible playbook 中,when 关键字用于条件执行任务。它允许你根据特定的条件来决定是否执行某个任务。这个功能非常强大,可以帮助你在不同的主机、不同的环境或不同的配置下灵活地执行任务。

when 表达式基于 Jinja2 模板语言,其中的变量主要来自: [1]

变量优先级 参考说明

when 关键字后面跟随一个条件表达式,当条件为真时,任务会执行;当条件为假时,任务会被跳过。

tasks:
- name: Install nginx on Debian
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == 'Debian'

when 关键字支持多种表达式,包括:

  • 简单条件

    • 基于变量 的条件:when: variable == 'value'

      - name: Install nginx only if nginx_install is true
      apt:
      name: nginx
      state: present
      when: nginx_install

      在这个示例中,nginx_install 是一个布尔变量。当 nginx_install 为真时,任务将执行。

    • 基于事实(facts) 的条件:when: ansible_facts['os_family'] == 'Debian'

      - name: Install nginx on Debian systems
      apt:
      name: nginx
      state: present
      when: ansible_facts['os_family'] == 'Debian'
  • 逻辑操作

    • 与操作when: condition1 and condition2
      - name: Install nginx on Debian systems
      apt:
      name: nginx
      state: present
      when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'
      当使用多个条件时,也先当于 and 操作
      tasks:
      - name: Shut down CentOS 6 systems
      ansible.builtin.command: /sbin/shutdown -t now
      when:
      - ansible_facts['distribution'] == "CentOS"
      - ansible_facts['distribution_major_version'] == "6"
    • 或操作when: condition1 or condition2
    • 非操作when: not condition
  • 列表和字典操作

    • 列表包含when: 'item' in mylist
      - name: Ensure package is installed if it is in the list
      apt:
      name: "{{ item }}"
      state: present
      loop:
      - nginx
      - git
      when: item in packages_to_install
    • 字典键存在when: 'key' in mydict
      - name: Run only if the key 'run_task' is present in mydict and its value is true
      debug:
      msg: "Running task"
      when: mydict.get('run_task', False)

      这个任务仅在 mydict 中存在键 run_task 且其值为真时执行。

      when: mydict.get('run_task', False)False 为默认值,如果 mydict 字典中不存在 run_task 键,mydict.get('run_task', False) 将返回 False。这种用法确保了在键不存在时,条件判断不会抛出错误。

  • 复杂条件

    • 组合多个条件when: (condition1 and condition2) or condition3

以下是一个完整的示例

---
- name: Example playbook using when conditions
hosts: all
become: yes

vars:
nginx_install: true
packages_to_install:
- nginx
- git
mydict:
run_task: true

tasks:
- name: Install nginx only if nginx_install is true
apt:
name: nginx
state: present
when: nginx_install

- name: Install nginx on Debian or Ubuntu
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'

- name: Ensure package is installed if it is in the list
apt:
name: "{{ item }}"
state: present
loop: "{{ packages_to_install }}"
when: item in packages_to_install

- name: Run only if the key 'run_task' is present in mydict and its value is true
debug:
msg: "Running task"
when: mydict.get('run_task', False)

引用 Facts 变量值

Ansible-playbook 运行过程中,默认会收集目标主机的 Facts 信息。可以在 Playbook 定义中引用这些值 [2]

原始的 facts 信息可以通过 setup 模块获取

ansible <hostname> -m ansible.builtin.setup

要在 playbook 或者 template 中引用,可以参考以下方法:

{{ ansible_facts['devices']['xvda']['model'] }}

{{ ansible_facts['nodename'] }}

playbook 示例

修改主机名

以下示例展示修改主机名可使用的 playbook,主机名称修改为 Inventory 中主机的主机名(Alias)

假设 Inventory 文件内容如下:

/etc/ansible/inventory/hosts
test_target1:
hosts:
ansible-target-centos79-1:
ansible_host: ansible-target-centos79-1
ansible_user: root
ansible-target-centos79-2:
ansible_host: ansible-target-centos79-2
ansible_port: 22
ansible_user: root

Playbook 内容如下

change_hostname.yml
---
- name: Change hostname based on inventory alias
hosts: test_target1
become: yes
tasks:
- name: Set hostname from alias
hostname:
name: "{{ inventory_hostname }}"

- name: Update /etc/hosts file with new hostname
lineinfile:
path: /etc/hosts
regexp: '^(127\.0\.1\.1\s+).*'
line: "127.0.1.1 {{ inventory_hostname }}"
state: present
when: ansible_facts['distribution'] == 'Ubuntu'

- name: Update /etc/sysconfig/network with new hostname (CentOS/RedHat)
lineinfile:
path: /etc/sysconfig/network
regexp: '^HOSTNAME=.*'
line: "HOSTNAME={{ inventory_hostname }}"
state: present
when: ansible_facts['distribution'] in ['CentOS', 'RedHat']

- name: Set hostname using hostnamectl
command: "hostnamectl set-hostname {{ inventory_hostname }}"
when: ansible_facts['distribution'] in ['CentOS', 'RedHat', 'Ubuntu']

- name: Reboot the system to apply changes
reboot:
msg: "Rebooting to apply hostname changes"
pre_reboot_delay: 5
post_reboot_delay: 30
reboot_timeout: 300

相关模板变量说明

模板变量 说明 示例
inventory_hostname 引用 Inventory 中的主机名称(Alias) {{ inventory_hostname }}

相关模块使用参考

模块 参考链接 示例
hostname hostname
lineinfile lineinfile
reboot reboot
command command

参考链接

Ansible playbooks

脚注

Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群 的快速编排。

Compose 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig

使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
Compose 中有两个重要的概念:

  • 服务 (service) : 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project) : 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

Compose 目前分为 2 个大版本: [1]

  • Compose V1 : 目前已经不提供官方支持。使用 Python 编写,通过 docker-compose 命令来调用。Compose V1docker-compose.yml 最开始要包含 version 命令,取值范围 2.03.8
  • Compose V2 : 使用 Go 编写,通过 docker compose 命令来调用。Compose V2 忽略 docker-compose.yml 最开始的 version 指令。Compose V2 向后兼容 Compose V1 版本
阅读全文 »

常用工具安装

查找 netstat 命令由哪个安装包提供

$ yum whatprovides /bin/netstat
net-tools-2.0-0.25.20131004git.el7.x86_64 : Basic networking tools
Repo : base
Matched from:
Filename : /bin/netstat

安装 net-tools

yum install -y net-tools
apt-get install -y net-tools
阅读全文 »

环境信息

  • Centos 7
  • ansible-core 2.16
  • Docker image python:3.12.3

安装

ansible-core 版本及 Python 版本支持对应关系

ansible-core Version Control Node Python Target Python / PowerShell
2.16 Python 3.10 - 3.12 Python 2.7
Python 3.6 - 3.12
Powershell 3 - 5.1

为了环境部署方便灵活,可以选择使用 python:3.12.3 的 Docker 镜像,以其为基础环境安装 ansible-core 2.16 或者直接使用 ansible 镜像启动。

# docker run --rm -it python:3.12.3 bash

# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# python --version
Python 3.12.3

# pip install ansible

# pip list
Package Version
------------ -------
ansible 9.5.1
ansible-core 2.16.6
cffi 1.16.0
cryptography 42.0.7
Jinja2 3.1.4
MarkupSafe 2.1.5
packaging 24.0
pip 24.0
pycparser 2.22
PyYAML 6.0.1
resolvelib 1.0.1
setuptools 69.5.1
wheel 0.43.0

# ansible --version
ansible [core 2.16.6]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.12/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.12.3 (main, May 14 2024, 07:23:41) [GCC 12.2.0] (/usr/local/bin/python)
jinja version = 3.1.4
libyaml = True

Ansible 配置说明

Ansible 主配置文件为 /etc/ansible/ansible.cfg其中的配置都可以被 ansible-playbook 或者命令行参数覆盖

ansible 默认会读取环境变量 ANSIBLE_CONFIG 指定的配置文件,当前路径下的 ansible.cfg,以及用户家目录下的 .ansible.cfg,以及 /etc/ansible/ansible.cfg 作为配置文件,已第一个找到的为准

常用配置说明

配置项 说明 示例
inventory 指定 inventory (主机列表)文件的路径,默认为 /etc/ansible/hosts
remote_user (未指定用户时)连接远程主机时使用的用户
remote_port 连接远程主机时使用的(默认)端口
host_key_checking 默认启用。检查主机密钥可以防止服务器欺骗和中间人攻击。
如果主机重新安装并且在 know_hosts 中拥有不同的密钥,ansible 会提示确认密钥。
如果要禁用此行为,可以配置为 False
ask_pass 默认为 False。当设置为 True 时,ansible 要求输入远端服务器的密码,即使配置了免密登录
log_path 日志文件,默认 /var/log/ansible.log
pattern 当没有给出 pattern 时的默认 pattern,默认值是 * 即所有主机

配置示例

/etc/ansible/ansible.cfg
[defaults]
# 设置默认的 inventory 文件路径
inventory = /etc/ansible/hosts

# 关闭主机密钥检查,方便新主机的快速添加
host_key_checking = False

# 设置默认的远程用户
remote_user = ansible

Inventory 配置说明

默认的 inventory 配置文件路径为 /etc/ansible/hosts,主要用来配置 Managed Hosts 列表 [3]

在命令行中,可以使用选项 -i <path> 指定不同的 inventory 或者可以在 ansible 配置文件 ansible.cfg 中使用指令 inventory 指定 inventory 文件位置。

命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory

inventory 文件支持多种格式,最常见的是 INIYAML 格式。

  • Ansible 默认创建了 2 个组:
    • all : 包含所有主机
    • ungrouped : 包含所有不在其他组(all 除外)中的所有主机。

      任何一个主机都会至少在 2 个组中,要么 all 和某个组中,要么 allungrouped

  • 一个主机可以包含在多个组中
  • parent/childchild 组被包含在 parent 组中。
    • INI 配置格式中,使用 :children 后缀配置 parent
    • YAML 配置格式中,使用 children: 配置 parent
      • 任何在 child 组中的主机自动成为 parent 组中的一员
      • 一个组可以包括多个 parentchild 组,但是不能形成循环关系
      • 一个主机可以在多个组中,但是在运行时,只能有一个实例存在,Ansible 会自动将属于多个组的主机合并。
  • 主机范围匹配。如果有格式相似的主机,可以通过范围格式使用一条指令来添加多台主机。
    • INI 配置格式中,使用以下格式
      [webservers]
      www[01:50].example.com

      ## 指定步长增长
      www[01:50:2].example.com

      db-[a:f].example.com
    • YAML 配置格式中,使用以下格式
      # ...
      webservers:
      hosts:
      www[01:50].example.com:

      ## 指定步长增长
      www[01:50:2].example.com:
      db-[a:f].example.com:

      范围格式 的第一项和最后一项也包括在内。即匹配 www01www50

Inventory 多配置文件支持

在主机数量较多,或者组织结构较复杂的情况下,使用单个 Inventory 配置文件会导致主机管理较为复杂。将单个 Inventory 配置文件按照项目或者组织或其他规则进行分割会显著降低维护复杂度。

Inventory 多配置文件支持,可以使用以下方法之一

  • 按照项目或者组织或其他规则将主机分割到多个配置中,命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory
  • 按照项目或者组织或其他规则将主机分割放置在多个文件中,并将所有文件统一放置在一个单独的目录中(如 /etc/ansible/inventory/),在命令行中使用选项 -i /etc/ansible/inventory/ 或者在 Ansible 配置文件(ansible.cfg)中使用指令 inventory 配置目录。

    注意事项: Ansible 使用字典顺序加载配置文件,如果在不同的配置文件中配置了 parent groupschild groups,那么定义 child groups 的配置要先用定义 parent groups 的文件加载,否则 Ansible 加载配置会报错: Unable to parse /path/to/source_of_parent_groups as an inventory source [4]

  • 使用 group_varshost_vars 目录分别存储组变量和主机变量 [7]

    注意事项: 组变量和主机变量必须使用 YAML 格式,合法的文件扩展名包括: .yamlyml.json 或者无文件扩展名

INI 格式的 Inventory

主机列表中的主机可以单独出现,也可以位于某个或者多个 组([] 开头的行)中

/etc/ansible/hosts
ansible-demo1.local
ansible-demo2.local

[webserver]
webserver1.local
webserver2.local

[nginxserver]
# 匹配多个主机:nginx1.local, nginx2.local, nginx3.local, nginx4.local
nginx[1:4].local variable1=value1 variable2=value2
nginx-bak.local ansible_ssh_host=10.10.0.1 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=PASSWORD
127.0.0.1 http_port=80 maxRequestPerChild=808


连接主机使用的常用配置说明 [6]

配置项 说明 示例
ansible_host 远程主机地址
ansible_port 远程主机端口
ansible_user 连接远程主机的 ssh 用户
Ansible 默认使用 control node 上执行 ansible 的用户名来连接远程主机 [9]
ansible_password 连接远程主机的 ssh 用户密码,建议使用 key 连接
ansible_ssh_private_key_file 连接远程主机的 ssh 私钥文件路径
ansible_become
ansible_sudo
ansible_su
用户权限提升
ansible_become_method 用户权限提升(escalation)的方式
ansible_become_user
ansible_sudo_user
ansible_su_user
用户权限提升(escalation)后的用户
ansible_become_password
ansible_sudo_password
ansible_su_password
sudo 密码(这种方式并不安全,强烈建议使用 --ask-sudo-pass)
ansible_become_exe
ansible_sudo_exe
ansible_su_exe
设置用户权限提升(escalation)后的可执行文件
ansible_connection 与主机的连接类型.比如:local, ssh 或者 paramiko
Ansible 1.2 以前默认使用 paramiko。1.2 以后默认使用 smart,smart 方式会根据是否支持 ControlPersist, 来判断 ssh 方式是否可行.
ansible_shell_type 目标系统的 shell 类型.默认情况下,命令的执行使用 sh 语法,可设置为 cshfish.
ansible_python_interpreter 目标主机的 python 路径
系统中有多个 Python, 或者命令路径不是 /usr/bin/python
阅读全文 »

YAML(YAML Ain’t Markup Language)是一种专门用于数据序列化的格式,常用于配置文件、数据交换等场景。它以其可读性和简洁性而受到开发者的青睐。YAML设计的目标是易于人类阅读和编写,并且易于与其他编程语言进行交互。下面是YAML语法的详细介绍

基本结构

  • 数据类型 :YAML 支持标量(如字符串、整数、浮点数)、序列(列表)和映射(字典)三种基本数据类型。

  • 缩进 :YAML 使用缩进表示结构层级关系,通常每个层级缩进两个或四个空格(禁止使用制表符)。

标量数据类型

标量(Scalars) 是单个的、不可分割的值。可以是字符串、整数或浮点数。标量可以是单行的值,也可以是多行的值

# 单行字符串
name: John Doe

# 整数
age: 35

# 浮点数
height: 5.9

# 布尔值
is_student: false

多行字符串可以使用字面量样式(|)或折叠样式(>):

# 字面量样式保留换行符
address: |
123 Main St
Anytown, WW 12345

# 折叠样式将连续的行合并为一行
description: >
This is a very long sentence
that spans several lines in the YAML
but will be rendered as a single
line in the output.

  • 可以显式指定数据类型,例如字符串可以用单引号或双引号包围
  • 字符串通常不需要引号,但如果含有特殊字符,则需要使用单引号或双引号。
  • true, false, null 等特定词汇表示布尔值和 Null
  • 时间和日期需要遵循ISO格式。

列表(Sequences)

列表(Sequences) 是一组按顺序排列的值(类似于数组或列表),用破折号加空格表示新的元素,每个列表项占一行,也需要正确缩进。

# 列表
hobbies:
- Reading
- Fishing
- Dancing

字典(Mappings)

映射/字典(Mappings) 是键值对的集合(类似于字典或哈希表),用冒号加空格表示键值对,键值对需要正确缩进

# 字典
person:
name: John Doe
age: 35
city: New York

嵌套结构

列表和字典可以嵌套使用,形成复杂的结构

# 嵌套的列表和字典
employees:
- name: John Doe
job: Developer
skills:
- Python
- SQL
- name: Jane Smith
job: Designer
skills:
- Photoshop
- Illustrator

锚点和别名

YAML支持定义锚点(&)和别名(*)来重用(引用)文档中的某部分,使用 & 创建一个锚点(alias),之后可以用 * 引用这个锚点。

使用 <<* 来合并已有(引用)的映射。

# 使用锚点和别名
defaults: &defaults
adapter: postgres
host: localhost

development:
<<: *defaults
database: dev_db

test:
<<: *defaults
database: test_db

# 字符串锚点和引用
name: &name_anchor "John Doe"
contact:
name: *name_anchor

注释

使用井号 # 开始一个注释,井号后面的内容将被视为注释,注释内容直到行尾。

多文档支持

一个 YAML 文件可以包含多个文档,每个文档用三个短横线 --- 分隔。

---
document1:
- item1
---
document2:
- item2

process-exporter Github

安装部署

process-exporter 生成 systemd 服务启动配置文件:

/etc/systemd/system/process_exporter.service
[Unit]
Description=process exporter
Documentation=process exporter

[Service]
ExecStart=/usr/bin/process-exporter -config.path /etc/prometheus/process_exporter.yml

[Install]
WantedBy=multi-user.target

建议将 process-exporter 的配置写入文件并使用 -config.path 指定配置文件。

配置进程监控

process-exporter 在配置文件中使用模板变量来配置筛选要监控的进程,可以使用的模板变量包括:

变量 说明 示例
{{.Comm}} 匹配进程的命令名(不包括路径)。主要来源于 /proc/<pid>/stat 输出中的第二部分
命令名是指进程执行时的名称。在 Linux 系统中,可以通过 /proc/<PID>/comm 文件来获取进程的命令名。例如,如果一个进程执行的命令是 /usr/local/bin/php,那么它的命令名就是 php
{{.ExeBase}} 匹配进程的可执行文件名,不包括路径
可执行文件名是指进程的完整路径的最后一个部分。例如,如果一个进程的完整路径是 /usr/local/bin/php,那么它的可执行文件名就是 php
{{.ExeFull}} 匹配进程的可执行文件的完整路径,例如 /usr/local/php73/bin/php
{{.Username}} 匹配进程的用户名
{{.Matches}} 匹配进程的命令行参数列表
{{.StartTime}}
{{.Cgroups}}

监控系统上的所有进程

要监控系统上的所有进程的运行情况,可以参考以下配置: [1]

/etc/prometheus/process_exporter.yml
process_names:
- name: "{{.Comm}}"
cmdline:
- '.+'
  • 以上配置会获取到系统上的所有进程(子进程被统计入父进程中
  • 假如配置中有多个匹配项,以上配置不能放到第一个,否则因为其可以匹配到系统中所有的进程,后续配置的匹配不会再有机会生效

监控系统上面指定进程

假如系统中运行了多个 php 的子进程,为了获取到各个子进程的统计数据,可以参考以下配置

/etc/prometheus/process_exporter.yml
process_names:

- name: php_pro1
cmdline:
- /usr/local/php73/bin/php
- /home/www/admin/artisan
- Pulldata

- name: php_schedule_run
cmdline:
- /usr/local/php73/bin/php
- /home/www/admin/artisan
- schedule:run

- name: php_artisan_queue
cmdline:
- /usr/local/php73/bin/php
- /home/www/admin/artisan
- queue:work

- name: "{{.Comm}}"
cmdline:
- '.+'

使用此配置,可以获取到系统中以下进程的统计数据:

  • /usr/local/php73/bin/php /home/www/admin/artisan Pulldata
  • /usr/local/php73/bin/php /home/www/admin/artisan schedule:run
  • /usr/local/php73/bin/php /home/www/admin/artisan queue:work

除可以获取到以上特定进程的统计数据外,还可以统计到除此之外的其他所有进程的统计数据。

因为配置中匹配进程的顺序的关系,假如系统中还有除此之外的其他 php 进程,那么由最后的 {{.Comm}} 统计到的 php 进程资源使用数据中不再包含前面 3 个特定进程的资源使用数据。

脚注