L B T

记 录 过 去 的 经 验

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

环境信息

  • Centos 7
  • Python 3

在 Telegram 中生成 Bot

  1. 首先在 telegram 中搜索 @BotFather,和其对话,根据提示创建 机器人,记录下生成的 token 信息

  2. 创建新的 Channel 或者 Group 或者将刚刚新建的 Bot 加入已有的 Channel/Group。

  3. 获取 ChatGroup ID,可以使用以下方法之一

    1. 添加机器人 @getmyid_bot 到 Channel,会自动显示 Chat ID

    2. 使用以下代码获取

      >>> import requests
      >>> response = requests.get(f'https://api.telegram.org/bot{token}/getUpdates')
      >>> data = response.json()
      >>> chat_id = data['result'][0]['message']['chat']['id']
      >>> chat_id
      -992754669

使用 curl 向 telegram 发送消息

$ curl -v "https://api.telegram.org/bot{token}/sendMessage?text=sa&chat_id=-992754669"

> GET /bot{token}/sendMessage?text=sa&chat_id=-992754669 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: api.telegram.org
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Fri, 02 Jun 2023 03:03:58 GMT
< Content-Type: application/json
< Content-Length: 276
< Connection: keep-alive
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, OPTIONS
< Access-Control-Expose-Headers: Content-Length,Content-Type,Date,Server,Connection
<
* Connection #0 to host api.telegram.org left intact
{"ok":true,"result":{"message_id":12,"from":{"id":5683237521,"is_bot":true,"first_name":"AlertManager","username":"AlertManager_Bot"},"chat":{"id":-992754669,"title":"AlertManager Test","type":"group","all_members_are_administrators":true},"date":1685675038,"text":"sa"}}

使用 python 向 telegram 发送消息

使用 requests 库

>>> import requests
>>> response = requests.get(f'https://api.telegram.org/bot{token}/sendMessage?text=sa&chat_id=-992754669')

>>> response.text
'{"ok":true,"result":{"message_id":13,"from":{"id":5683237521,"is_bot":true,"first_name":"AlertManager","username":"AlertManager_Bot"},"chat":{"id":-992754669,"title":"AlertManager Test","type":"group","all_members_are_administrators":true},"date":1685675769,"text":"sa"}}'

使用 telegram 库

需要安装 python-telegram-bot

pip install --upgrade python-telegram-bot

发送消息代码

>>> import telegram
>>> import asyncio
>>> bot = telegram.Bot(token='5683231111:AAHzaGf0oRg8A')
>>> async def send_telegram_message():
... response = await bot.send_message(chat_id=-992754669, text="la")
... print(response)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(send_telegram_message())
Message(channel_chat_created=False, chat=Chat(api_kwargs={'all_members_are_administrators': True}, id=-992754669, title='AlertManager Test', type=<ChatType.GROUP>), date=datetime.datetime(2023, 6, 2, 3, 39, 16, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='AlertManager', id=5683237521, is_bot=True, username='MS_AlertManager_Bot'), group_chat_created=False, message_id=14, supergroup_chat_created=False, text='la')

如果需要在非异步环境中(例如 Django 试图函数) 运行以上异步代码,会报错: RuntimeError: There is no current event loop in thread 'Thread-1'。需要特殊处理,可以使用 asyncio.run() 函数来运行异步代码,它可以在非异步环境中创建一个新的事件循环并运行异步函数。

Django 视图中参考代码如下

def send_message_to_tg(chat_id: int, text: str):
''' 发送消息到 tg'''
bot = telegram.Bot(token=tg_bot_token)

async def send_telegram_message():
response = await bot.send_message(chat_id=chat_id, text=text)
print(response)
# loop = asyncio.get_event_loop()
# loop.run_until_complete(send_telegram_message())
asyncio.run(send_telegram_message())

本文档主要做为需要安装或升级 Nginx 版本或者需要重新编译 Nginx 为其添加新模块时的参考。Nginx 服务常用配置说明

环境信息

  • Centos 7 5.4.225-1
  • nginx stable 1.24.0

编译安装 Nginx

编译安装 Nginx 之前,首先需要安装依赖包 [1]

pcre

cd /tmp
wget github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.tar.gz
tar -zxf pcre2-10.42.tar.gz
cd pcre2-10.42
./configure
make
sudo make install

zlib

cd /tmp
wget http://zlib.net/zlib-1.2.13.tar.gz
tar -zxf zlib-1.2.13.tar.gz
cd zlib-1.2.13
./configure
make
sudo make install

openssl

cd /tmp
wget --no-check-certificate http://www.openssl.org/source/openssl-1.1.1t.tar.gz
tar -zxf openssl-1.1.1t.tar.gz
cd openssl-1.1.1t
./config shared zlib
make install

编译安装 Nginx

下载 Nginx stable 版本编译安装

wget https://nginx.org/download/nginx-1.24.0.tar.gz
tar zxf nginx-1.24.0.tar.gz
cd nginx-1.24.0

要启用或者停用指定的 Nginx 自带模块,参考 Nginx 编译配置选项说明

此处编译配置添加第三方模块 nginx-module-vts 以支持 Prometheus。执行以下命令编译 Nginx 并添加第三方模块 nginx-module-vtsNginx 和 nginx-module-vts 版本兼容列表

wget https://github.com/vozlt/nginx-module-vts/archive/refs/tags/v0.2.2.tar.gz
tar -xf v0.2.2.tar.gz

./configure --prefix=/usr/local/nginx-1.24.0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream --with-stream_ssl_module \
--with-openssl=/tmp/openssl-1.1.1t \
--with-http_v2_module \
--add-module=nginx-module-vts-0.2.2/

make
make install

编译安装后的软件包,只需要安装好依赖,便可以迁移到其他机器上面使用,本文档编译安装后的软件包下载链接

为 Nginx 配置 systemd 管理配置文件

为了能使用 systemctl 管理源码编译安装的 nginx,可以为其使用以下配置文件将其托管到 systemd

/usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/local/nginx-1.24.0/sbin/nginx -t
ExecStart=/usr/local/nginx-1.24.0/sbin/nginx
ExecReload=/usr/local/nginx-1.24.0/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Prometheus 采集 Nginx 监控数据

参考步骤安装 nginx-module-vts 模块,以支持 Prometheus 采集 Nginx 统计数据。

如果要统计 Nginx 所有的 vhost 数据,则将 nginx-module-vts 模块相关配置放置于 http 模块内,否则可以在只想要监控(统计)的 vhost (server 配置段) 中添加配置。

nginx-module-vts 模块相关配置命令说明:

命令 说明 用法示例
vhost_traffic_status_zone 定义 vhost_traffic_status 模块使用的共享内存区域。用于存储虚拟主机的流量统计信息 vhost_traffic_status_zone shared_memory_name size;
shared_memory_name 是共享内存区域的名称,size 是共享内存区域的大小。
vhost_traffic_status_filter_by_host 按主机名过滤虚拟主机状态信息
默认会将流量全部计算到第一个 server_name 上;启用后,只会显示与请求的主机名匹配的虚拟主机状态信息。
vhost_traffic_status_filter_by_host on;
vhost_traffic_status_filter_by_set_key 根据自定义键值对来过滤虚拟主机的状态信息 vhost_traffic_status_filter_by_set_key $host$request_uri;
vhost_traffic_status_filter_by_set_zone 过滤器使用的共享内存区域
vhost_traffic_status_display 用于显示虚拟主机状态信息的格式
支持 jsonCSVhtml
vhost_traffic_status_display_format html;
vhost_traffic_status_display_format 用于显示虚拟主机状态信息的字段格式。
可以选择显示的字段有:request、status、request_time、request_length、request_method、request_uri、request_length、request_time、request_time_counter、request_time_counter_overflows、request_time_min、request_time_max、request_time_avg、request_time_median、request_time_percentile。
vhost_traffic_status_display_format field1 field2 ...;

为了获取所有域名的统计信息,在 Nginx 的 http 模块内添加以下配置:

nginx.con
http {
...
vhost_traffic_status_zone;

vhost_traffic_status_filter_by_host on;

server {
listen 8888;
server_name localhost;
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format json;
}

}
}

重载配置后查看请求内容:

# curl localhost:8888/status
{"hostName":"testhost","moduleVersion":"v0.2.2","nginxVersion":"1.24.0","loadMsec":1713418497362,"nowMsec":1713418504352,"connections":{"active":7,"reading":0,"writing":1,"waiting":6,"accepted":7,"handled":7,"requests":14},"sharedZones":{"name":"ngx_http_vhost_traffic_status","maxSize":1048575,"usedSize":10587,"usedNode":3},"serverZones":{"api.testdomain.com":{"requestCounter":12,"inBytes":9330,"outBytes":6249,"responses":{"1xx":0,"2xx":12,"3xx":0,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0},"requestMsecCounter":11,"requestMsec":0,"requestMsecs":{"times":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1713418503612,1713418503612,1713418503612,1713418503612,1713418503612,1713418503962,1713418503965,1713418503965,1713418503966,1713418503966,1713418504330,1713418504331],"msecs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,1,3,3,0,0]},"requestBuckets":{"msecs":[],"counters":[]},"overCounts":{"maxIntegerSize":18446744073709551615,"requestCounter":0,"inBytes":0,"outBytes":0,"1xx":0,"2xx":0,"3xx":0,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0,"requestMsecCounter":0}},"src.testdomain.ph":{"requestCounter":1,"inBytes":393,"outBytes":309,"responses":{"1xx":0,"2xx":0,"3xx":1,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0},"requestMsecCounter":0,"requestMsec":0,"requestMsecs":{"times":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1713418500180],"msecs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"requestBuckets":{"msecs":[],"counters":[]},"overCounts":{"maxIntegerSize":18446744073709551615,"requestCounter":0,"inBytes":0,"outBytes":0,"1xx":0,"2xx":0,"3xx":0,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0,"requestMsecCounter":0}},"*":{"requestCounter":13,"inBytes":9723,"outBytes":6558,"responses":{"1xx":0,"2xx":12,"3xx":1,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0},"requestMsecCounter":11,"requestMsec":0,"requestMsecs":{"times":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1713418500180,1713418503612,1713418503612,1713418503612,1713418503612,1713418503612,1713418503962,1713418503965,1713418503965,1713418503966,1713418503966,1713418504330,1713418504331],"msecs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,1,3,3,0,0]},"requestBuckets":{"msecs":[],"counters":[]},"overCounts":{"maxIntegerSize":18446744073709551615,"requestCounter":0,"inBytes":0,"outBytes":0,"1xx":0,"2xx":0,"3xx":0,"4xx":0,"5xx":0,"miss":0,"bypass":0,"expired":0,"stale":0,"updating":0,"revalidated":0,"hit":0,"scarce":0,"requestMsecCounter":0}}},"upstreamZones":{"::nogroups":[{"server":"127.0.0.1:12000","requestCounter":5,"inBytes":4154,"outBytes":3351,"responses":{"1xx":0,"2xx":5,"3xx":0,"4xx":0,"5xx":0},"requestMsecCounter":11,"requestMsec":2,"requestMsecs":{"times":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1713418503962,1713418503965,1713418503965,1713418503966,1713418503966],"msecs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,1,3,3]},"requestBuckets":{"msecs":[],"counters":[]},"responseMsecCounter":11,"responseMsec":2,"responseMsecs":{"times":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1713418503962,1713418503965,1713418503965,1713418503966,1713418503966],"msecs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,1,3,3]},"responseBuckets":{"msecs":[],"counters":[]},"weight":0,"maxFails":0,"failTimeout":0,"backup":false,"down":false,"overCounts":{"maxIntegerSize":18446744073709551615,"requestCounter":0,"inBytes":0,"outBytes":0,"1xx":0,"2xx":0,"3xx":0,"4xx":0,"5xx":0,"requestMsecCounter":0,"responseMsecCounter":0}}]}}

统计信息输出结果支持多种格式:

  • localhost:8888/status/format/json - Json
  • localhost:8888/status/format/html - Html
  • localhost:8888/status/format/jsonp - Jsonp
  • localhost:8888/status/format/prometheus - Prometheus
  • localhost:8888/status/format/control - control

在 Prometheus 中添加以下 Targets 配置抓取 nginx-module-vts 模块暴露出的统计信息

- job_name: "Nginx"
metrics_path: '/status/format/prometheus'
static_configs:
- targets: ['IPADDRESS:8888']
labels:
Department : 'OP'

在 Prometheus 中检查抓取到的数据

常见错误

error while loading shared libraries

Nginx 编译安装成功后,启动报错

$ /usr/local/nginx-1.24.0/sbin/nginx -t
/usr/local/nginx-1.24.0/sbin/nginx: error while loading shared libraries: libpcre2-8.so.0: cannot open shared object file: No such file or directory

问题原因 为 Nginx 在系统的库文件路径中未找到已经安装的 libpcre2-8.so.0 库文件。可以通过以下方式验证

  1. 搜索 libpcre2-8.so.0,可以看到系统上已经存在此库文件 /usr/local/lib/libpcre2-8.so.0
    $ find / -name libpcre2-8.so.0
    /usr/local/lib/libpcre2-8.so.0
  2. 检查此库文件是否在系统已加载的库文件中。执行以下命令搜索系统已经加载的库文件,发现没有 /usr/local/lib/libpcre2-8.so.0
    $ ldconfig -p | grep libpcre
    libpcre32.so.0 (libc6,x86-64) => /lib64/libpcre32.so.0
    libpcre16.so.0 (libc6,x86-64) => /lib64/libpcre16.so.0
    libpcreposix.so.0 (libc6,x86-64) => /lib64/libpcreposix.so.0
    libpcrecpp.so.0 (libc6,x86-64) => /lib64/libpcrecpp.so.0
    libpcre.so.1 (libc6,x86-64) => /lib64/libpcre.so.1
  3. 检查系统共享库文件的查找路径的配置文件 /etc/ld.so.conf,发现其中不包括路径 /usr/local/lib/,因此位于此路径下的共享库文件无法被搜索到
    $ cat /etc/ld.so.conf
    include ld.so.conf.d/*.conf


要解决此问题,可以使用以下方法之一:

  • 添加 /usr/local/lib/ 到系统共享库查找路径配置文件 /etc/ld.so.conf

    /etc/ld.so.conf
    include ld.so.conf.d/*.conf
    /usr/local/lib/

    执行以下命令,使配置生效

    ldconfig
  • 设置系统环境变量 LD_LIBRARY_PATH,这个变量定义了系统共享库的查找目录。将 /usr/local/lib 添加到此变量的值中,要永久生效需要将其写入配置文件,如 ~/.bash_profile

    export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"
  • 创建符号链接

    ln -s /usr/local/lib/libpcre2-8.so.0 /usr/local/nginx-1.24.0/sbin/libpcre2-8.so.0

    或者

    ln -s /usr/local/lib/libpcre2-8.so.0 /lib64/libpcre2-8.so.0

SSL modules require the OpenSSL library

执行以下命令执行编译前配置时报错 ./configure: error: SSL modules require the OpenSSL library.

# ./configure --prefix=/usr/local/nginx-1.24.0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream --with-stream_ssl_module \
--with-http_v2_module \
--add-module=nginx-module-vts-0.2.2/

checking for PCRE2 library ... found
checking for OpenSSL library ... not found
checking for OpenSSL library in /usr/local/ ... not found
checking for OpenSSL library in /usr/pkg/ ... not found
checking for OpenSSL library in /opt/local/ ... not found

./configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl=<path> option.

此报错原因为未找到 OpenSSL 的库文件。

针对此场景,可以通过在编译配置时指定 OpenSSL 的源码中库文件的具体位置(--with-openssl=/tmp/openssl-1.1.1t),参考以下命令

./configure --prefix=/usr/local/nginx-1.24.0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream --with-stream_ssl_module \
--with-openssl=/tmp/openssl-1.1.1t \
--with-http_v2_module \
--add-module=nginx-module-vts-0.2.2/

Error 127

Nginx 执行 make 命令时报错: /bin/sh: line 2: ./config: No such file or directory

# ./configure --prefix=/usr/local/nginx-1.24.0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream --with-stream_ssl_module \
--with-openssl=/usr/local/lib64/ \
--with-http_v2_module \
--add-module=nginx-module-vts-0.2.2/

# make
make -f objs/Makefile
make[1]: Entering directory `/root/nginx-1.24.0'
cd /usr/local/lib64/ \
&& if [ -f Makefile ]; then make clean; fi \
&& ./config --prefix=/usr/local/lib64//.openssl no-shared no-threads \
&& make \
&& make install_sw LIBDIR=lib
/bin/sh: line 2: ./config: No such file or directory
make[1]: *** [/usr/local/lib64//.openssl/include/openssl/ssl.h] Error 127
make[1]: Leaving directory `/root/nginx-1.24.0'
make: *** [build] Error 2

错误信息表明在编译 nginx 时,make 命令无法找到 OpenSSL 的配置脚本 config。此脚本位于 OpenSSL 的源码目录中。可以通过 --with-openssl=/tmp/openssl-1.1.1t 指定。
修改编译前的配置命令如下:

./configure --prefix=/usr/local/nginx-1.24.0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream --with-stream_ssl_module \
--with-openssl=/tmp/openssl-1.1.1t \
--with-http_v2_module \
--add-module=nginx-module-vts-0.2.2/

make
make install

getpwnam(“nginx”) failed

nginx 报错

nginx: the configuration file /usr/local/nginx-1.24.0/conf/nginx.conf syntax is ok
nginx: [emerg] getpwnam("nginx") failed
nginx: configuration file /usr/local/nginx-1.24.0/conf/nginx.conf test failed

问题原因nginx 用户不存在,创建 nginx 用户或者修改配置文件,使用已有的用户运行 nginx

参考链接

Nginx 官网文档

脚注

环境信息

  • Prometheus 2.44.0
  • Grafana 9.5.2
  • Kubernetes 1.24

Kubernetes 相关指标

Kubernetes 中部署并监控 Kubernetes 集群参考

配置 Prometheus 监控 Kubelet 之后可以采集到 Kubelet 监控指标。

配置 Prometheus 读取 cAdvisor 之后可以通过 cAdvisor 采集到容器相关的监控指标。

指标名称 类型 说明 示例
kubelet_pod_start_duration_seconds_count Pod 启动的时间
kubelet_pod_start_duration_seconds_bucket Pod 启动的时间的延迟直方图数据 kubelet_pod_start_duration_seconds_bucket{le="0.5"}
kubelet_running_pods 运行的 Pod 的数量
kubelet_running_containers 运行的 Containers 的数量
kubelet_runtime_operations_errors_total Kubelet 和 CRI 交互产生的错误(类型)
kubelet_started_containers_total Kubelet 启动的 Container 总数
kubelet_started_pods_total Kubelet 启动的 Pod 总数
kubelet_volume_stats_available_bytes PV Volume 可以使用的磁盘空间
kube_node_status_allocatable
kube_node_status_capacity
节点的可分配的 资源 数量 kube_node_status_allocatable{resource="pods"}
节点可分配的 Pod 的数量
kubelet_started_pods_total Counter 已启动的 Pod 数量
container_cpu_usage_seconds_total Counter Container 使用的 CPU
container_memory_usage_bytes Gauge Pod 使用的内存 container_memory_usage_bytes{namespace="default"}
kube_pod_container_status_restarts_total Counter Pod 的重启次数

nginx-ingress-controller 相关指标

配置 Prometheus 监控 Ingress-Nginx-Controller 指标 后,Prometheus 可以读取到 Ingress-Nginx-Controller 暴露的监控指标。

Grafana 中配置使用 Ingress-Nginx-Controller 指标示例

指标名称 类型 说明 示例
nginx_ingress_controller_requests Counter Ingress Nginx Controller 接收到的所有请求数,,包括各个状态码 irate(nginx_ingress_controller_requests[2m]) - 请求速率
nginx_ingress_controller_nginx_process_connections 连接数,包括各个状态码
nginx_ingress_controller_request_duration_seconds_sum 请求持续时间的总和
请求持续时间是从请求进入 Ingress 控制器开始,到响应返回给客户端结束的整个时间
nginx_ingress_controller_request_duration_seconds_count 请求持续时间的计数。 计算平均请求持续时间:平均请求持续时间 = 请求持续时间总和 / 请求持续时间计数
nginx_ingress_controller_ingress_upstream_latency_seconds_sum upstream 占用时间的总和
upstream 占用时间是指请求从 Ingress 到达 upstream(backend)服务器的时间
nginx_ingress_controller_ingress_upstream_latency_seconds_count upstream 上游占用时间的计数 计算平均上游占用时间:平均上游占用时间 = 上游占用时间总和 / 上游占用时间计数。

node 相关指标

主机信息

包括 CPU 架构、内核版本、操作系统类型、主机名等,集中在指标 node_uname_info 中。

CPU

指标名称 类型 说明 示例
node_cpu_seconds_total Counter CPU 使用时间 node_cpu_seconds_total{mode="idle"} - CPU 空闲时间

统计节点 CPU 使用率

100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

Memory

指标名称 类型 说明 示例
node_memory_MemTotal_bytes Gauge 总的内存
node_memory_MemFree_bytes Gauge 空闲内存
node_memory_Cached_bytes Gauge Cache 内存
node_memory_Buffers_bytes Gauge Buffers 内存

统计节点的 内存使用率

(node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Cached_bytes - node_memory_Buffers_bytes) / node_memory_MemTotal_bytes * 100

Network

指标名称 类型 说明 示例
node_network_receive_bytes_total Counter 网卡接收的流量
node_network_transmit_bytes_total Counter 网卡发送的流量

网卡流量带宽

irate(node_network_receive_bytes_total{device!~"cni0|docker.*|flannel.*|veth.*|virbr.*|lo",kubernetes_io_hostname=~"$node"}[$prometheusTimeInterval])

irate(node_network_transmit_bytes_total{device!~"cni0|docker.*|flannel.*|veth.*|virbr.*|lo",kubernetes_io_hostname=~"$node"}[$prometheusTimeInterval])

环境信息

  • Python 3.10
  • Django 4.1

在 Project/App 的 models.py 文件中创建 model,当 model 定义完成,Django 会自动生产一个后台管理接口,允许认证用户添加、更改和删除对象,只需在管理站点上注册模型即可 [1]

创建 model

在 Project/App 的 models.py 文件中创建 model

models.py
from django.db import models

# 公司部门
class Department(models.Model):
name = models.CharField(max_length=24, unique=True, help_text="部门名称",verbose_name='名称')
shortName = models.CharField(max_length=8, unique=True, help_text="部门名称简称",verbose_name='简称')
manager = models.ForeignKey('Emplyee', on_delete=models.CASCADE, help_text="部门老大")
comment = models.CharField(max_length=256, blank=True, help_text="备注信息",verbose_name='备注')

def __str__(self):
return self.shortName

class Meta:
# 管理后台显示的 model 名,最后面没有 's'
verbose_name_plural = "部门"

# 管理后台显示的 model 名,最后面有 's',显示为 '部门s'
verbose_name = "部门"

# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"

Django 模型字段参考

对修改后的 model 进行 migrate,以使在数据库中变更更改。

python manage.py makemigrations
python manage.py migrate

model 注册到后台

在 Project/App 的 admin.py 文件中注册 model

admin.py
from django.contrib import admin

# 假如 app 为 servers,导入 models
from servers import models

admin.site.site_header = "My Admin"
admin.site.site_title = "My Admin"

@admin.register(models.Department)
class DepartmentAdmin(admin.ModelAdmin):
list_display = ('id','name','shortName','manager','comment')
list_display_links = ('id','name','shortName','manager','comment')

更多有关 admin 配置方法,请参考 Django admin 配置

阅读全文 »

环境信息

  • xshell7

常用配置

字体配置

(菜单栏)查看 > 工具栏 > 标准按钮

中文字体和英文字体需要单独配置,建议配置默认会话属性

(菜单栏)文件 > 默认会话属性,找到 外观 分别配置 字体 以及 亚洲字体:

阅读全文 »

伴手礼选择

伴娘伴手礼

类别 产品类别推荐 详情参考
香薰、香水 香薰礼盒
化妆品
花果茶
喜糖礼盒 佳偶良缘 喜糖礼盒

参考链接:
20款百元左右的高级感伴手礼

伴郎伴手礼

类别 产品类别推荐 详情参考
过宋小湯四季养生礼盒
UMTEA 关心茶礼盒
葡萄酒 名庄95分 蓝风铃甜白葡萄酒
点心 马卡龙甜点糕点铁盒

根据更新的比特币价格数据和计算,如果每年元旦买入BTC,次年元旦卖出,直到2024年,每年的投资回报率(ROI)如下:

  • 2013年买入,2014年卖出的ROI:约 5390.75%
  • 2014年买入,2015年卖出的ROI:约 -57.01%
  • 2015年买入,2016年卖出的ROI:约 37.21%
  • 2016年买入,2017年卖出的ROI:约 131.78%
  • 2017年买入,2018年卖出的ROI:约 1243.49%
  • 2018年买入,2019年卖出的ROI:约 -72.10%
  • 2019年买入,2020年卖出的ROI:约 92.07%
  • 2020年买入,2021年卖出的ROI:约 308.63%
  • 2021年买入,2022年卖出的ROI:约 62.51%
  • 2022年买入,2023年卖出的ROI:约 -58.27%
  • 2023年买入,2024年卖出的ROI:约 166.06%

环境信息

  • aws-cli/2.9.15

aws cli 安装更新说明

aws cli 基础配置及说明

常见用法

查看 aws 帮助信息

aws help

查看子命令帮助信息

aws ec2 help

配置认证信息时指定鉴权信息对应的 Profile

aws configure --profile source-account

aws 命令常用选项

选项 说明 示例
--region 指定区域,aws 区域列表 aws --region ap-east-1 ec2 describe-instances
--profile 指定配置文件名称。当需要同时操作多个账号上面的 S3 目标时,可以为每个账号指定 profile 名称,在后续操作时使用选项 --profile 指定要使用的 Profile
阅读全文 »

环境信息

  • Kubernetes 1.29

kubeadm 初始化集群

Network setup

组件的 advertise IP 地址选择

Kubernetes 中的组件(如 KubeadmKube-apiserver 等)在初始化启动时,都需要在节点(主机)上找到一个合适的 IP 作为组件的 advertising/listening 的地址。[1]

默认情况下,此 IP 是主机上默认路由对应的网卡所在的 IP。

# ip route show
default via 172.31.16.1 dev eth0
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
10.244.3.0/24 via 10.244.3.0 dev flannel.1 onlink
10.244.4.0/24 via 10.244.4.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.31.16.0/20 dev eth0 proto kernel scope link src 172.31.26.11

如果系统上有多个默认路由,组件会尝试使用第一个默认路由对应的网卡所在的 IP。如果系统上没有默认路由,并且未明确为组件配置 IP,组件会初始化失败并退出

组件选择的 IP 地址将会作为 X.509 证书的 SAN(Subject Alternative Name) 的一部分。因此在系统初始化运行之后修改 IP 需要重新签发证书并重启相关组件。

Pod 网段选择

Pod 的网段必须不能和主机网络重叠,如果选用的网络插件的网络和主机的网段重叠,必须为网络插件选择合适的和主机不同的网段,在集群初始化时通过参数 --pod-network-cidr 配置,并在安装网络插件时在其 YAML 文件中修改为对应的网段。 [4]

control-plane-endpoint 参数说明

--control-plane-endpoint 选项用来配置 api-server 的共享地址,可以是域名或者负载均衡器的 IP。 [2]

如果是单主节点的 Kubernetes 集群,想要扩展成为多个 Master 节点(高可用),初始化时没有 --control-plane-endpoint,是不被支持的。

因此为了后期可以由单个 Master 节点扩展为多个 Master 节点,即高可用,初始化节点时,建议加上此选项配置 api-server 的负载均衡地址。

阅读全文 »

环境信息

  • Centos7 5.4.212-1
  • Docker 20.10.18
  • containerd.io-1.6.8
  • kubectl-1.25.0
  • kubeadm-1.25.0
  • kubelet-1.25.0

几乎所有的 Kubernetes 对象都包含两个嵌套的对象字段:

  • spec - 对象的期望状态(desired state)的描述信息
  • status - 对象当前的状态(current state

Kubernetes 系统的目标就是不停的调整对象的当前状态(current state)直到和期望状态(desired state)匹配。

常用字段说明

必需字段

在想要创建的 Kubernetes 对象所对应的 .yaml 文件中,必须配置的字段如下:[1]

  • apiVersion - 创建该对象所使用的 Kubernetes API 的版本
  • kind - 想要创建的对象的类别
  • metadata - 帮助唯一标识对象的一些数据,包括一个 name 字符串、UID 和可选的 namespace
  • spec - 你所期望的该对象的状态

metadata

帮助唯一标识对象的一些数据,包括一个 name 字符串、UID 和可选的 namespace

集群中的每一个对象都有一个 名称name)来标识在同类资源中的唯一性。name 也用来作为 url 中的资源名称 [2]

每个 Kubernetes 对象也有一个 UIDuid)来标识在整个集群中的唯一性。

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

标签和选择算符

标签(labels) 是附加到 Kubernetes 对象(比如 Pod)上的键值对。 标签旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 标签可以用于组织和选择对象的子集。标签可以在创建时附加到对象,随后可以随时添加和修改。 每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。[3]

通过 标签选择算符,客户端/用户可以识别一组对象。标签选择算符 是 Kubernetes 中的核心分组原语。

对于某些 API 类别(例如 ReplicaSet)而言,两个实例的标签选择算符不得在命名空间内重叠, 否则它们的控制器将互相冲突,无法确定应该存在的副本个数。

比较新的资源,例如 JobDeploymentReplicaSetDaemonSet, 也支持基于集合的需求。

selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}

matchLabels 是由 {key,value} 对组成的映射。 matchLabels 映射中的单个 {key,value} 等同于 matchExpressions 的元素, 其 key 字段为 keyoperatorIn,而 values 数组仅包含 valuematchExpressions 是 Pod 选择算符需求的列表。 有效的运算符包括 InNotInExistsDoesNotExist。 在 InNotIn 的情况下,设置的值必须是非空的。 来自 matchLabelsmatchExpressions 的所有要求都按 逻辑与 的关系组合到一起 – 它们必须都满足才能匹配

字段选择器

字段选择器(Field selectors) 允许你根据一个或多个资源字段的值 筛选 Kubernetes 资源

下面是一些使用字段选择器查询的例子:

  • metadata.name=my-service
  • metadata.namespace!=default
  • status.phase=Pending

下面这个 kubectl 命令将筛选出 status.phase 字段值为 Running 的所有 Pod:

kubectl get pods --field-selector status.phase=Running

不同的 Kubernetes 资源类型支持不同的字段选择器。 所有资源类型都支持 metadata.namemetadata.namespace 字段。 使用不被支持的字段选择器会产生错误

你可在字段选择器中使用 ===!==== 的意义是相同的)操作符。 例如,下面这个 kubectl 命令将筛选所有不属于 default 命名空间的 Kubernetes 服务:

kubectl get services  --all-namespaces --field-selector metadata.namespace!=default

同标签和其他选择器一样, 字段选择器可以通过使用逗号分隔的列表组成一个选择链。 下面这个 kubectl 命令将筛选 status.phase 字段不等于 Running 同时 spec.restartPolicy 字段等于 Always 的所有 Pod:

kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

你能够跨多种资源类型来使用字段选择器。 下面这个 kubectl 命令将筛选出所有不在 default 命名空间中的 StatefulSetService

kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
阅读全文 »

环境信息

  • Filebeat 8.8

Filebeat 启动之后,会根据配置文件中配置的数据收集路径启动 1 个或者多个 inputs。针对匹配到的每个文件,Filebeat 都会启动一个对应的 harvester,每个 harvester 读取一个单独的文件内容,并将其中的新内容发送到 libbeatlibbeat 会整合数据并将其发送到配置的 output [1]

如果 input 类型为 loginput 会负责找到配置中匹配到的文件,并为每个文件启动一个 harvester。每个 input 都运行在自己独立的 Go routine (例程) 中。 [4]

Filebeat 工作原理

Filebeat 会将收割(harvest) 的每个文件的状态存储到 registry。因此如果要让 Filebeat 从头开始收集数据,只需要删除 registry 文件即可。可以使用命令 filebeat export config 找到 data 目录,registry 位于其中。

安装

Filebeat 官方安装文档

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.8.2-x86_64.rpm
rpm -vi filebeat-8.8.2-x86_64.rpm

systemctl enable --now filebeat

filebeat command-line interface

filebeat 命令常用功能 [3]

子命令 说明 示例
help 查看命令帮助信息
filebeat help COMMAND_NAME [FLAGS]
export 导出 配置 等信息 export 使用
modules 模块管理命令。用来 enable 或者 disable 位于 modules.d 中的 模块
filebeat modules disable MODULE
filebeat modules enable MODULE
filebeat modules list
Data collection modules
run 启动 filebeat
test 测试配置文件 或者到 output 的连接
filebeat test config
filebeat test output
version 显示当前版本信息
阅读全文 »

和田玉的分类

山料和籽料

按照矿产分类,主要分为籽料与山料两种。

山料,是籽料的前身

山料

和田玉山料 产自昆仑山脉之中,属于原生矿,被称为 璞玉

从质地上说,有的山料的结构较为粗糙,颗粒比较明显或带石性,不带皮色,油性差,有的山料靠近外部有红糖的颜色。也有结构细密,油润度极好的优质山料。

山料因为没有受到河流的冲刷,自始至终都深藏在岩体中,缺乏外力的打磨,看起来比较干涩,所以外形大多平淡无奇,有棱有角,表面也比较干涩,绺裂现象明显。

籽料

和田玉籽料 是采自河床或者河床泥土中,经过几十万年的侵蚀打磨而得到的玉石。有时又被称为 水籽

籽料是由山料在地质活动时冲刷或滚落到河里,由河水冲刷(还有风化、风干等物理反应一起作用)形成的。籽料产自 河流中下游,是次生矿。产自河流上游的被称为 山流水料。籽料因为长久受到河流的冲刷,一般为卵石形状,表面很光滑圆润,带皮色。

和山料的存在环境不同,导致籽料有了以下特性:

  • 籽料常年在河水中浸泡,水流的压力使它的肉质变得更加紧密,水流的冲刷使它变的更加温润油腻,形成了它独特的质地和油润感;
  • 河水中存在很多的矿物质和微量元素,长时间的水流冲刷和加压过程中,部分矿物质会沉淀到籽料中,形成各种颜色的籽料皮子。带有皮子的籽料,价格有大大提升

籽料开采出来,外观上看就与鹅卵石一般无二,各个颜色都有,只不过他是和田玉再形成的鹅卵石。仔细观察籽料表面会发现上面密密麻麻都是一些小孔,因为这些小孔跟我们皮肤上的毛孔相似被称之为毛孔或者皮孔。和田玉籽料一般有皮色和皮孔,就算没有皮色,籽料上还是能够找到均匀的毛细孔,这是籽料独有的标志。而山料则没有皮色皮孔。

一般情况下,籽料都会拥有或深或浅的皮色,表面还会有明显的小凹坑(也就是俗称的皮孔),这是玉石长时间在水中冲刷、浸泡和磕碰造成的。而山料由于生长环境固定,不存在皮色和皮孔。

同时,由于籽料长年累月泡在水中,水里的微生物和微量元素会渗入到玉石中,所以会造成局部呈现或黄或红或黑的颜色,也就是 沁色。而这一点在山料身上,就非常不明显。

籽料的水润度是明显高于山料的,如果比较籽料和山料制作的成品,会很容易发现籽料表面质地非常润泽、光滑、细腻。而山料作品,即使经过抛光处理,表面仍会干涩,缺乏光滑的油润感,这一点用手触摸时尤为明显。

由于 和田玉籽料的密度比山料大,所以同等体积的情况下,籽料相对山料比较重

山料也有很多可以跟顶级籽料相媲美的。比如 1995 年于田县开采的 8 吨和田玉山料,白度细度等各个方面都是顶级。因品质极佳,入市后引起了轰动,后被称之位“95于田料”。时至今日,“95于田料” 在业内也是传说中的料子,被很多业内人士公认为 羊脂级。著名的和氏璧就是一块山料。

和田玉器的市场价格中羊脂玉最高、籽料高、山流水次之、山料更次之。

和田玉结构

和田玉籽料内部结构致密,用肉眼几乎看不到内部结构;而再好的山料,还是能看到其松软质地的结构。

籽料由于有外力的挤压、打磨,所以密度要明显高过山料。籽料的话,无论是青籽还是白籽,内部结构都是致密的,用肉眼几乎看不到内部结构。而山料,无论结构多致密,在强光手电筒下,总是能看到松软的质地结构。

广义的籽料

今天的籽料已不是传统意义上的和田籽料了。在广义和田玉的范围内,籽料也有了更多种类。

新疆产的岫玉籽料

新疆除了有和田玉籽料,还出产一种颜色或绿或黑绿色等,里面也有黑点存在的岫玉。岫玉中品质好的,外观与和田玉籽料很相似,并且在市场上的和田籽料中也能看到相当数量的岫玉籽料,大家要留意。

来自俄罗斯的“籽料”

俄罗斯玉,近年来随着和田料的减少而逐渐成为软玉舞台的有力竞争者。

从玉材来看,俄料95%都是山料,但也有籽料,只是俄料中的“籽料”并未达到籽料定义的产状玉料:籽料由于长期的冲刷搬运碰撞,玉质形态韧性都达到了特别的质感,而俄料中的“籽料”其实没有这个长期的过程,严格意义上只能算和田玉的山流水料。

辽宁产的河磨料

河磨料是国内确切命名的两种籽料之一,另一种是和田籽料。“河磨”,从河里磨出来的玉,名字起得很传神,可能因为河水的冲击力较小,河磨料多见厚皮料。

另外,近几年贵州罗甸也出产白度尚可的软玉,透闪石含量达95%,也是广义和田玉中的一种。罗甸玉石性很重,料子干涩,缺乏油性,其实所谓的“籽料”也只能用来骗骗小白玩友;广西大化玉则是这几年才出现的玉种,也是广义和田玉中的一种,大化玉里有籽料,质地也很细腻,有兴趣的宝友可以玩一玩。

环境信息

  • Centos-7 3.10.0-1062.9.1
  • Docker 19.03.15
  • containerd.io-1.4.13
  • kubectl-1.25.0
  • kubeadm-1.25.0
  • kubelet-1.25.0

kubeadm 常用命令

kubeadm 命令官方参考文档

创建集群

kubeadm init --pod-network-cidr=10.244.0.0/16 --cri-socket=unix:///var/run/cri-dockerd.sock
选项 说明 示例
--pod-network-cidr 指定 pod 的 cidr,安装 CNI 插件时,配置的 CIDR 要和此处一致
--service-cidr service 使用的 CIDR
--cri-socket 配置集群使用的 CRI,不指定时系统会扫描主机,如果有多个可用 CRI,会出现提示
--apiserver-advertise-address 手动配置 api-server 的 Advertise IP 地址。
不配置的情况下,系统默认选择主机上的默认路由对应网卡上面的 IP
--control-plane-endpoint 配置 api-server 的共享地址,可以是域名或者负载均衡器的 IP
单节点的 Master 后期需要扩展为多节点(高可用)时,需要有此配置,否则不支持(kubeadm)扩展

添加节点到集群

kubeadm join 172.31.10.19:6443 --token 8ca35s.butdpihinkdczvqb --discovery-token-ca-cert-hash sha256:b2793f9a6bea44a64640f99042f11c4ff6 \ 
--cri-socket=unix:///var/run/cri-dockerd.sock

其中的 token 可以在 master 上使用以下命令查看

$ kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
8ca35s.butdpihinkdczvqb 19h 2022-09-14T02:54:55Z authentication,signing The default bootstrap token generated by 'kubeadm init'. system:bootstrappers:kubeadm:default-node-token

默认情况下,令牌会在 24 小时后过期。如果要在当前令牌过期后将节点加入集群, 则可以通过在控制平面节点上运行以下命令来创建新令牌:

kubeadm token create

如果你没有 --discovery-token-ca-cert-hash 的值,则可以通过在控制平面节点上执行以下命令链来获取它[1]

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
阅读全文 »

filebeat 上传数据到 elasticsearch 问题汇总

filebeat 上传数据到 elasticsearch 报错

适用版本信息说明

  • filebeat 7
  • elasticsearch 7

filebeat 7.5.2 上传数据到 Elasticsearch 报错:

# journalctl -f -u filebeat
{"type":"illegal_argument_exception","reason":"Validation Failed: 1: this action would add [2] total shards, but this cluster currently has [6924]/[3000] maximum shards open;"}

此错误原因是由于 Elasticsearch 的集群中打开的分片数量超过了集群的最大分片限制。在 Elasticsearch 中,每个索引由多个分片组成,而集群有一个设置的最大分片数限制。这个限制是为了防止分片数过多导致性能问题。

错误消息 {"type":"illegal_argument_exception","reason":"Validation Failed: 1: this action would add [2] total shards, but this cluster currently has [6924]/[3000] maximum shards open;"} 显示当前集群已有 6924 个分片,超过了 3000 个的限制。

要解决这个问题,可以考虑以下几个选项:

  1. 调整 Elasticsearch 集群设置,增加最大分片数限制

    可以通过更改 Elasticsearch 配置来增加最大分片数的限制。但请注意,这可能会导致性能问题,尤其是如果硬件资源有限的话。

    这可以通过修改 cluster.max_shards_per_node 设置来实现

    PUT /_cluster/settings
    {
    "persistent": {
    "cluster.max_shards_per_node": "新的分片数限制"
    }
    }

    获取 Elasticsearch 集群的最大分片数限制

    curl -X GET "http://[your_elasticsearch_host]:9200/_cluster/settings?include_defaults=true&pretty"

  2. 删除一些不必要的索引 :如果有些索引不再需要,可以删除它们来减少分片数。

    curl -X DELETE "localhost:9200/my_index"
    curl -X DELETE "localhost:9200/logstash-2021.11.*"
  3. 合并一些小索引:如果有很多小的索引,可以考虑将它们合并为更大的索引,以减少总分片数。

  4. 优化现有索引的分片策略:可以优化索引的分片数量,例如,通过减少每个索引的主分片数量。

filebeat 错误

filebeat 配置上传数据到 elasticsearch 报错

适用版本信息说明

  • filebeat 7
  • elasticsearch 7

使用以下 filebeat 配置文件

/etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
paths:
- /home/logs/laravel-2023*
tags: ["admin-log"]
close_timeout: 3h
clean_inactive: 72h
ignore_older: 70h
close_inactive: 5m

output.elasticsearch:
hosts: ["1.56.219.122:9200", "1.57.115.214:9200", "1.52.53.31:9200"]
username: "elastic"
password: "passwd"
index: "logstash-admin-%{+yyyy.MM.dd}"
setup.template.enabled: true
setup.template.name: "logstash-admin"
setup.template.pattern: "logstash-admin-*"

filebeat 启动后报错,elasticsearch 上未创建相应的索引,关键错误信息 Failed to connect to backoff(elasticsearch(http://1.57.115.214:9200)): Connection marked as failed because the onConnect callback failed: resource 'filebeat-7.5.2' exists, but it is not an alias

journalctl -f -u filebeat
INFO [index-management] idxmgmt/std.go:269 ILM policy successfully loaded.
ERROR pipeline/output.go:100 Failed to connect to backoff(elasticsearch(http://1.57.115.214:9200)): Connection marked as failed because the onConnect callback failed: resource 'filebeat-7.5.2' exists, but it is not an alias
INFO pipeline/output.go:93 Attempting to reconnect to backoff(elasticsearch(http://1.57.115.214:9200)) with 3 reconnect attempt(s)
INFO elasticsearch/client.go:753 Attempting to connect to Elasticsearch version 7.6.2
INFO [index-management] idxmgmt/std.go:256 Auto ILM enable success.
INFO [index-management.ilm] ilm/std.go:138 do not generate ilm policy: exists=true, overwrite=false
INFO [index-management] idxmgmt/std.go:269 ILM policy successfully loaded.
ERROR pipeline/output.go:100 Failed to connect to backoff(elasticsearch(http://1.56.219.122:9200)): Connection marked as failed because the onConnect callback failed: resource 'filebeat-7.5.2' exists, but it is not an alias
INFO pipeline/output.go:93 Attempting to reconnect to backoff(elasticsearch(http://1.56.219.122:9200)) with 3 reconnect attempt(s)

这表明 Filebeat 无法正常连接到 Elasticsearch 集群。出现这个问题的主要原因可能为:

  • 索引/别名冲突: Filebeat 试图创建或使用一个名为 filebeat-7.5.2 的索引或别名,但这个资源在 Elasticsearch 中已存在且不是一个别名。解决方法为 删除或重命名冲突索引

  • ILM 配置问题

    使用此配置文件,解决 索引/别名冲突 问题后,filebeat 运行正常,但是 Elasticsearch 上未创建配置中的索引 logstash-admin-*,而是将数据上传到了索引 filebeat-7.5.2-*。这个问题是由 ILM 导致,可以禁用 ILM。参考以下配置,禁用 ILM (setup.ilm.enabled: false)

    /etc/filebeat/filebeat.yml
    filebeat.inputs:
    - type: log
    paths:
    - /home/logs/laravel-2023*
    tags: ["admin-log"]
    close_timeout: 3h
    clean_inactive: 72h
    ignore_older: 70h
    close_inactive: 5m

    output.elasticsearch:
    hosts: ["1.56.219.122:9200", "1.57.115.214:9200", "1.52.53.31:9200"]
    username: "elastic"
    password: "passwd"
    index: "logstash-admin-%{+yyyy.MM.dd}"
    setup.ilm.enabled: false
    setup.template.enabled: true
    setup.template.name: "logstash-admin"
    setup.template.pattern: "logstash-admin-*"

环境信息

  • Centos 7 3.10.0-1062

curl 命令示例

常见选项

选项 说明 示例
-v 输出详细信息
-0 内容输出到指定文件或设备 curl -o /dev/null
-s 不输出任何信息(http 响应内容除外)
-w 自定义输出内容 curl -s -o /dev/null -w %{http_code} https://csms.tech
-I 只获取响应头部信息 curl -I https://csms.tech
--resolve yourdomain.com:443:source_ip domain:port 解析为指定的 IP 使用方法参考
curl -v -H "Host: admin.test.com" --resolve admin.test.com:443:52.52.2.9 https://admin.test.com
-H, --header 自定义 http 请求头部 -H "Host: admin.test.com"
阅读全文 »

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

阅读全文 »

nc

安装

Centos 下安装

yum install -y nc

Windows 下安装

Windows 下需要 下载 netcat 运行程序

下载后直接解压,将 nc.exe 复制到 C:\Windows\System32 目录或将 nc.exe 添加到系统 path 环境变量中

使用示例

选项 说明 示例
-v
-vvv
打印详细信息
-t 使用 TCP 协议,默认为 TCP 协议
-u 使用 UDP 协议,默认为 TCP 协议
-z 不发送数据,效果为立即关闭连接,快速得出测试结果

注意事项:客户端测试使用 localhost 作为主机名时,会优先被解析为 IPv6 地址,如果端口监听在 IPv4 地址,会导致测试结果不可达

测试 udp 端口连通性

以下输出表示端口可达

# nc -vuz ip/domain 8472
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to ip:8472.
Ncat: UDP packet sent successfully
Ncat: 1 bytes sent, 0 bytes received in 2.01 seconds.

以下输出表示端口不可达

# nc -vuz 127.0.0.1 8473
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:8473.
Ncat: Connection refused.