L B T

记 录 过 去 的 经 验

环境信息

  • 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)

脚注

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
阅读全文 »

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 个特定进程的资源使用数据。

脚注

Nextcloud All-in-One

Nextcloud All-in-One 在一个 Docker 容器中提供了方便部署和维护的 Nextcloud 方式。[1]

使用 docker compose 部署

为方便后期管理及迁移,建议使用 docker compose 方式部署。docker-compose.yml 参考文件如下: [2]

docker-compose.yml
version: "3"

services:
nextcloud-aio-mastercontainer:
image: nextcloud/all-in-one:latest
container_name: nextcloud-aio-mastercontainer
ports:
- "8000:80"
- "8080:8080"
- "8443:8443"
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro

volumes:
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer
driver: local
driver_opts:
type: none
o: bind
device: /opt/Nextcloud/data/

使用 docker compose 方式部署注意事项:

  • name: nextcloud_aio_mastercontainer: Volume 名称必须是 nextcloud_aio_mastercontainer,否则会报错找不到卷 nextcloud_aio_mastercontainer: It seems like you did not give the mastercontainer volume the correct name? (The 'nextcloud_aio_mastercontainer' volume was not found.). Using a different name is not supported since the built-in backup solution will not work in that case!

启动成功后,根据提示在浏览器中打开 Nextcloud AIO setup 页面并记录页面显示的密码

You should be able to open the Nextcloud AIO Interface now on port 8080 of this server!
E.g. https://internal.ip.of.this.server:8080

根据页面提示登陆,跟随页面提示进行新实例初始化。

初始化过程中要提供域名,系统会自动为域名颁发证书(使用系统 443 端口映射到容器中的 8443 端口)

默认的 Nextcloud AIO 未部署反向代理,要使用反向代理请参考文档: Reverse Proxy Documentation

Nextcloud AIO 使用的端口说明

脚注

环境信息

  • Centos 7
  • Prometheus Server 2.4
  • Node Exporter v1.4.0
  • Grafana v9.2.5

安装

在 Docker 中安装 Prometheus Server

创建 Prometheus Server 配置文件,如 /root/prometheus/prometheus.yml,内容如下 [1]

/data/prometheus/prometheus.yml
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'

# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.

static_configs:
- targets: ['localhost:9090']

使用 Docker 启动时挂载此文件,作为 Prometheus Server 的配置文件,之后需要修改配置,可以直接修改此文件。

docker run -d -p 9090:9090 \
--name prometheus \
-v /root/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus

启动后,可以通过 $Prometheus_IP:9090 访问 Prometheus Server UI

阅读全文 »

Prometheus ValKey & Redis Metrics Exporter

Prometheus Redis Metrics Exporter 下载页面

redis_exporter 安装

wget https://github.com/oliver006/redis_exporter/releases/download/v1.59.0/redis_exporter-v1.59.0.linux-amd64.tar.gz
tar -xf redis_exporter-v1.59.0.linux-amd64.tar.gz
mv redis_exporter-v1.59.0.linux-amd64/redis_exporter /usr/bin/

redis_exporter 生成 systemd 服务配置文件 /usr/lib/systemd/system/redis_exporter.service

/usr/lib/systemd/system/redis_exporter.service
[Unit]
Description=redis_exporter
After=syslog.target
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/redis_exporter
Restart=always
RestartSec=10
StartLimitInterval=100

[Install]
WantedBy=multi-user.target

启动 redis_exporter 服务

# systemctl daemon-reload

# systemctl enable --now redis_exporter

# systemctl status redis_exporter
● redis_exporter.service - redis_exporter
Loaded: loaded (/usr/lib/systemd/system/redis_exporter.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2024-04-30 10:45:58 CST; 5s ago
Main PID: 12126 (redis_exporter)
CGroup: /system.slice/redis_exporter.service
└─12126 /usr/bin/redis_exporter

Apr 30 10:45:58 ip-172-31-26-219.us-west-1.compute.internal systemd[1]: Started redis_exporter.
Apr 30 10:45:58 ip-172-31-26-219.us-west-1.compute.internal redis_exporter[12126]: time="2024-04-30T10:45:58+08:00" level=info msg="Redis Metrics Exp...md64"
Apr 30 10:45:58 ip-172-31-26-219.us-west-1.compute.internal redis_exporter[12126]: time="2024-04-30T10:45:58+08:00" level=info msg="Providing metrics...rics"
Hint: Some lines were ellipsized, use -l to show in full.

redis_exporter 服务启动后,默认启动 9121 端口提供 Metrics 数据供 Prometheus 抓取。

redis_exporter 配置

redis 实例及认证信息配置

如果要通过一个 redis_exporter 实例监控多个 Redis 实例,可以参照以下配置文件配置 Redis 实例及其认证信息,如果无需密码认证,则保留密码项为空。

/etc/redis_exporter_pwd_file.json

{
"redis://localhost:7380": "paswd12",
"redis://localhost:7381": "paswd12",
"redis://localhost:7382": "paswd12",
"redis://172.31.19.9:7380": "paswd12",
"redis://172.31.19.9:7381": "paswd12",
"redis://172.31.19.9:7382": ""
}

修改 redis_exporter 启动参数,使其读取上面配置的实例和其认证信息

/usr/bin/redis_exporter -redis.password-file /etc/redis_exporter_pwd_file.json

配置 Prometheus 抓取 redis_exporter 指标

参考以下配置使用文件发现的方式配置被监控的 Redis 实例


scrape_configs:
- job_name: 'redis_exporter_targets'
file_sd_configs:
- files:
- targets-redis-instances.yml
metrics_path: /scrape
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: <<REDIS-EXPORTER-HOSTNAME>>:9121

## config for scraping the exporter itself
- job_name: 'redis_exporter'
static_configs:
- targets:
- <<REDIS-EXPORTER-HOSTNAME>>:9121

targets-redis-instances.yml 文件内容包含 Targets 内容:

targets-redis-instances.yml
- labels:
label1: value1
targets: [ "redis://redis-host-01:6379", "redis://redis-host-02:6379"]
阅读全文 »