L B T

记 录 过 去 的 经 验

Grafana 是一款用 GO 语言开发的开源数据可视化工具,可以做数据监控和数据统计,带有告警功能。

基础概念

组织(Organization) 与用户(User)

Organization 相当于一个 Namespace,一个 Organization 完全独立于另一个 Organization,包括 datasourcedashboard 等,创建一个 Organization 就相当于打开了一个全新的视图,所有的 datasourcedashboard 等都需要重新创建。一个用户(User) 可以属于多个 Organization。

User 是 Grafana 里面的用户,用户可以有以下 角色

  • admin - 管理员权限,可以执行任何操作。
  • editor - p不可以创建用户不可以新增 Datasource可以创建 Dashboard**
  • viewer - 仅可以查看 Dashboard
  • read only editor - 允许用户修改 Dashboard,但是 不允许保存

数据源 Datasource

Grafana 中操作的数据集、可视化数据的来源

Dashboard

在 Dashboard 页面中,可以组织可视化数据图表。

  • Panel - 在一个 Dashboard 中,Panel 是最基本的可视化单元。通过 Panel 的 Query Editor 可以为每一个 Panel 添加查询的数据源以及数据查询方式。每一个 Panel 都是独立的,可以选择一种或者多种数据源进行查询。一个 Panel 中可以有多个 Query Editor 来汇聚多个可视化数据集
  • Row - 在 Dashboard 中,可以定义一个 Row,来组织和管理一组相关的 Panel

Variables

在 Dashboard 的设置页面中,有 Variables 页面,在其中可以为 Dashboard 配置变量,之后可以在 Panel 的 Query Editor 中使用这些预定义的变量。变量的值也可以是通过表达式获取的值。也可以在 Panel 的标题中使用变量

例如以下 Variables 配置

Node    label_values(kubernetes_io_hostname)

在 Dashboard 中定义了这些变量后,可以在 Panel 的 Query Editor 中使用,在 Query Editor 中使用了 Variables 中定义的变量后,在 Dashboard 的顶部下拉菜单中可以选择预定义的变量的值(需要在定义 Variables 时配置 Show on dashboardLabel and Value 以使在 Dashboard 顶部显示下拉菜单),Panel 中的 Query 表达式就会使用这些变量的值进行计算以及显示图表。

阅读全文 »

环境信息

  • centos7
  • python3
  • Django 4

ModuleNotFoundError: No module named ‘MySQLdb’

ModuleNotFoundError: No module named ‘MySQLdb’

django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.

解决方法

pip3 install pymysql

编辑文件./python36/lib/python3.6/site-packages/django/db/backends/mysql/__init__.py, 输入以下内容

import pymysql 
pymysql.install_as_MySQLdb()
阅读全文 »

本文档主要做为需要安装或升级 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 官网文档

脚注

Certbot 是 Let’s Encrypt SSL 官方推荐的 ACME 协议客户端,它是一个 Python 程序,且包含模块化插件支持。Let’s Encrypt 的根证书浏览器支持广泛,且支持泛域名。但单个证书的有效期为 90 天,以防止滥用。

安装 Certbot

官方安装步骤参考

以下步骤演示在 Python3 环境中安装 Certbot 及其相关依赖

  1. 安装 certbot
    pip install certbot
  2. 申请证书时,要使用 DNS 方式验证域名所有权并且 DNS 使用 Cloudflare 的情况下,可以安装 certbot-dns-cloudflare 插件实现自动验证,参考以下命令安装 certbot-dns-cloudflare,此模块需要 cloudflare 模块的支持
    pip install cloudflare
    pip install certbot-dns-cloudflare
    安装完成后检查相关模块和版本。其中 cloudflare 版本需要最低为 2.3.1 [1]
    # pip list
    certbot 2.10.0
    certbot-dns-cloudflare 2.10.0
    cloudflare 2.19.2
    以上模块安装完成后,即可使用 certbot 申请域名证书,并支持 Cloudflare DNS 的自动验证。

基于 Cloudflare DNS 的自动验证申请域名证书

参考步骤安装 certbot 及 Cloudflare DNS 插件后 即可使用 certbot 自动请求 Cloudflare DNS 创建申请证书时需要的 DNS 记录自动完成域名归属权的验证过程。

certbot 支持的 Cloudflare 相关的参数如下

参数 说明 示例
--dns-cloudflare 使用 Cloudflare 的 DNS 插件自动验证域名归属权
--dns-cloudflare-credentials 请求 Cloudflare 的授权配置文件
--dns-cloudflare-propagation-seconds 请求 Cloudflare DNS 添加相关 DNS 记录后,让 ACME 服务等待多少秒再验证 DNS 记录。主要用来防止 DNS 记录添加后,缓存 DNS 服务器未来得及更新最新记录。
默认为 10

Cloudflare Credentials 说明

假设有 Cloudflare 账号的 Global API Key,则 Credentials 配置文件内容参考如下

cloudflare.ini
# Cloudflare API credentials used by Certbot
dns_cloudflare_email = cloudflare@example.com
dns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234

申请证书的具体命令如下,如果是第一次申请,需要根据提示填写自己的邮箱信息并同意许可协议,邮箱用于接受之后系统发送的错误或者域名证书过期等信息

certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d example.com \
-d www.example.com

如果是非交互式环境,可以使用参数 --email your-email@example.com--agree-tos 自动绑定邮箱并同意许可

阅读全文 »

环境信息

  • 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

阅读全文 »

Nginx 服务配置

全局通用配置

nginx.conf
user nginx nginx;    

# 建议设置为 cpu 核心数或者 cpu 核心数的 2 倍,进程会包含一个 `master process`,多个 `worker process`
# master process 负责绑定端口、调度进程等,不负责业务的处理
# worker process 是业务进程,负责业务的处理
worker_processes auto;

# 一个 worker 进程可以打开的最大的 fd 个数,受 Linux 内核限制
# 理论值应该是系统最多打开文件数(ulimit -n)与 nginx 进程数相除
# 可通过 ulimit 设置或修改系统文件:`/etc/securit/limits.conf`
worker_rlimit_nofile 1024;

# cpu 亲和性设置
worker_cpu_affinity 0001 0010 0100 1000;

# 工作进程调度优先级,-20 到 19 之间的值,值越小越优先调用。
# 如果系统同时运行多个任务,你可能需要提高 nginx 的工作进程的优先级
worker_priority 0;

# ssl 硬件加速服务器,需要硬件支持
# ssl_engine ssl_engine device;

# nginx 是否以守护进程运行,是否让 nignx 运行于后台;调试时可为 off,使得所有信息直接输出在控制台
daemon on | off;

# events 模块中包含 nginx 中所有处理连接的设置。
events {
# 每个 worker 进程允许的最多连接数,
# nginx 服务最大连接数:worker_processes * worker_connections (受 worker_rlimit_nofile 限制)
worker_connections 1024;
use epoll;

# 是否允许一次性地响应多个用户请求
multi_accept on;

# 是否打开 nginx 的 accept 锁;此锁能够让多个 worker 进行轮流地、序列化地与新的客户端建立连接;
# 而通常当一个 worker 进程的负载达到其上限的 7/8,master 就尽可能不将请求调度至 worker.
accept_mutex on | off;
}

# HTTP 模块控制着 nginx http 处理的所有核心特性
http {
include mime.types;
default_type application/octet-stream;

# 是否在错误页面中显示和响应头字段中发出 nginx 版本号。
# 安全考虑建议关闭
server_tokens on | off | string;

# 是否启用 sendfile 内核复制模式功能。作为静态服务器可以提供最大的 IO 访问速度。
sendfile on | off;

# 尽快发送数据,否则会在数据包达到一定大小后再发送数据。这样会减少网络通信次数,降低阻塞概率,但也会影响响应及时性。
# 比较适合于文件下载这类的大数据通信场景。
tcp_nodelay on|off;

# 单位s,适当降低此值可以提高响应连接数量
keepalive_timeout 65;

# 一次长连接上允许的最大请求数
keepalive_requests 100;

# 禁止指定浏览器使用 keepalive
keepalive_disable msie6|none;

# 读取 http 请求首部的超时时长。如果客户端在此时间内未传输整个头,则会向客户端返回 408(请求超时)错误
client_header_timeout 1;

# 读取 http 请求包体的超时时间。
client_body_timeout 2;

# 发送响应的超时时长。超时后连接将关闭。
send_timeout 5;

# http 请求包体的最大值,常用于限定客户端所能够请求的最大包体,根据请求首部中的 Content-Length 来检查,以避免无用的传输。
client_max_body_size 1m;

# 限制客户端每秒传输的字节数,默认为0,表示没有限制。单位 Byte/s
limit_rate 0;

# nginx 向客户端发送响应报文时,如果大小超过了此处指定的值,则后续的发送过程开始限速,单位 Byte
limit_rate_after 0;

# 是否忽略不合法的 http 首部,默认为 on,off 意味着请求首部中出现不合规的首部将拒绝响应。
ignore_invalid_headers on|off;

# 用户访问的文件不存在时,是否将其记录到错误日志中。
log_not_found on|off;

# nginx 使用的 dns 地址,及缓存解析结果的时间
resolver 8.8.8.8 [valid=time] [ipv6=on|off];

# dns 解析超时时间
resolver_timeout 2;

# 是否打开文件缓存功能,max:用于缓存条目的最大值,
# inactive:某缓存条目在指定时长内没有被访问过时,将自动被删除,即缓存有效期,通常默认为 60s。
open_file_cache off;
open_file_cache max=N [inactive=time];

# 是否缓存文件找不到或没有权限访问等相关信息。
open_file_cache_errors on | off;

# 多长时间检查一次缓存中的条目是否超出非活动时长。
# 建议值:小于等于 open_file_cache inactive
open_file_cache_valid 60;

# 在 open_file_cache inactive指 定的时长内被访问超过此处指定的次数时,才不会被删除(删除低命中率的缓存)。
open_file_cache_min_uses 2;

# 开启内容压缩,可以有效降低客户端的访问流量和网络带宽
gzip on | off;

# 内容超过最少长度后才开启压缩,太短的内容压缩效果不佳,且会浪费系统资源。
# 压缩长度会作为 http 响应头 Content-Length 字段返回给客户端。 建议值:64
gzip_min_length length;

# 压缩级别,默认值为 1。范围为1~9级,压缩级别越高压缩率越高,但对系统性能要求越高。建议值:4
gzip_comp_level 1~9;

# 压缩内容类型,默认为 text/html;。只压缩 html 文本,一般我们都会压缩 js、css、json 之类的,可以把这些常见的文本数据都配上。
如:text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_types mime-type …;

# 自动显示目录
autoindex on;

# off : 以人类易读的方式显示文件大小,on:以 bytes 显示文件大小
autoindex_exact_size off;

# 定义限制区域,imit_req_zone 只能放在 http {} 内,使用此限制可以在 http {} (对服务器内所有的网站生效)、server {} (对具体的一个网站生效)或 location {} (对具体的一个网址生效)
# 此区域名称为 test,可根据需求自定义; 10m 表示此区域存储 key($binary_remote_addr)使用的大小
# 存储大小,一般 1m 空间大约能保存 1.6 万条 IP 地址,空间满了新数据会覆盖旧数据
# rate=1r/m ,限制访问请求频率为每分钟 1 次,可根据需要自行设置,1r/s 是 1 秒 1 次,时间单位只能选择 s (秒)或 m (分),最低频率限制是每分钟 1 次访问请求
# rate=10r/m,1分钟最多访问 10 次,同时不能超过 1r/6s,即 6s 内最多访问 1 次。超过 1r/6s 返回 503
limit_req_zone $binary_remote_addr zone=test:10m rate=1r/m;

# 定义日志格式
log_format main '{ time: $time_iso8601|'
'http_host:$http_host|'
'cdn_ip:$remote_addr|'
'request:$request|'
'request_method:$request_method|'
'http_user_agent:$http_user_agent|'
'size:$body_bytes_sent|'
'responsetime:$request_time|'
'upstreamtime:$upstream_response_time|'
'upstreamhost:$upstream_addr|'
'upstreamstatus:$upstream_status|'
'url:$http_host$uri|'
'http_x_forwarded_for:$clientRealIp|'
'status:$status}';

# server 负责具体的 http 服务器实现
server {
listen 80 [default_server] [rcvbuf=SIZE] [sndbuf=SIZE] [ssl];

# 可使用通配符*或正则表达式(~开头),多个域名先精确匹配,再通配,再正则,'_'表示空主机头
server_name _ ;

access_log logs/access.log main;
error_log logs/access.err.log;

# 跨域配置
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With';
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials: true;

location / {
# web 资源路径
root html;

# 定义默认页面,从左往右匹配
index index.html index.htm;

# 自左向右读取指定路径,找到即停止,如果都不存在,返回一个错误码
try_files $uri $uri.html $uri/index.html =404;

# 自左向右读取指定路径,找到即停止,如果都不存在,返回一个 uri
try_files $uri $uri.html $uri/index.html /404.html;
}

location /i/ {
# 路径别名,只能用于 location 中。
# 访问 http://a.com/i/a.html, 资源路径为:/data/www/html/a.html
# 若是root指令,访问 http://a.com/i/a.html,资源路径为:/data/www/html/i/a.html
alias /data/www/html/;
}

# 对于某个请求发生错误,如果匹配到错误码,重定向到新的 url
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

# 对于某个请求发生错误,如果匹配到错误码,重定向到新的 url,同时可以更改返回码
error_page 404 =200 /404.html;
}

# 包含其他配置文件
include vhosts/*.conf;
}


阅读全文 »

环境信息

  • 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 官网文档

环境信息

  • Centos 7 5.4.212-1
  • Docker 20.10.18
  • containerd.io-1.6.8
  • kubectl-1.24.7
  • kubeadm-1.24.7
  • kubelet-1.24.7

kubernetes 环境安装前配置

升级内核版本

Centos 7 默认的内核版本 3.10 在运行 kubernetes 时存在不稳定性,建议升级内核版本到新版本

Centos 7 升级内核
  • Centos 7 默认的内核版本 3.10 使用的 cgroup 版本为 v1,Kubernetes 的部分功能必须使用 cgroup v2 来进行增强的资源管理和隔离 [13]

    使用以下命令检查系统使用的 cgroup 版本

    stat -fc %T /sys/fs/cgroup/

    如果输出是 cgroup2fs表示使用 cgroup v2

    如果输出是 tmpfs表示使用 cgroup v1

  • User Namespaces 功能需要 Linux 6.3 以上版本,tmpfs 才能支持 idmap 挂载。并且其他功能(如 ServiceAccount 的挂载)也需要此功能的支持 [14]

关闭 SELinux

kubernetes 目前未实现对 SELinux 的支持,因此必须要关闭 SELinux

sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

集群中所有计算机之间具有完全的网络连接

配置集群所有节点的防火墙,确保所有集群节点之间具有完全的网络连接。

  • 放通节点之间的通信
  • 确保防火墙允许 FORWARD 链的流量
    /etc/sysconfig/iptables
    *filter
    :INPUT DROP [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [4:368]

    -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -i lo -j ACCEPT

    # kubernetes nodes
    -A INPUT -m comment --comment "kubernetes nodes" -s 172.31.5.58 -j ACCEPT
    -A INPUT -m comment --comment "kubernetes nodes" -s 172.31.5.68 -j ACCEPT
    -A INPUT -m comment --comment "kubernetes nodes" -s 172.31.0.230 -j ACCEPT

    -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT -m comment --comment "k8s ingress http,https"


    ...

    -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
    -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
    -A INPUT -j REJECT --reject-with icmp-host-prohibited
    COMMIT
阅读全文 »

在 Ubuntu 上安装软件包主要通过使用 apt 命令来完成。apt 是高级包装工具(Advanced Package Tool)的缩写,提供了一个易用的命令行界面,用于处理软件包的安装、更新和删除等操作。

环境信息

  • Ubuntu 22

apt

查看软件包信息

  • 查看系统已安装的软件包

    apt list --installed

    apt list 列出系统上所有可用的软件包,包括已安装的软件包可供安装的软件包

  • 列出特定的软件包

    apt list <package-name>
  • 搜索特定软件包是否已安装

    apt list --installed  <package-name>
  • 查看软件包的依赖关系

    apt depends <package_name>

下载软件包

  • 下载软件包但不安装
    apt download <package_name>

安装软件包

  • 更新软件包列表。在安装新软件包之前,最好先更新本地软件包列表,以确保你安装的是最新版本的软件包。

    sudo apt update

    此命令会从配置的源中检索新的软件包列表。

  • 安装软件包。安装软件包的基本命令格式为:

    sudo apt install <package_name>
  • 安装特定版本的软件包

    如果你需要安装软件包的特定版本,可以通过指定版本号来完成安装。首先,使用 apt policy 命令查找可用版本

    apt policy <package_name>

    然后,安装特定版本的软件包

    sudo apt install <package_name>=<version>

    sudo apt install nginx=1.18.0-0ubuntu1
  • 安装推荐的软件包。

    当安装某些软件包时,APT 可能会建议安装一些推荐的软件包以增强功能。默认情况下,apt install 命令会安装推荐的软件包。 如果你不想安装推荐的软件包,可以使用 --no-install-recommends 选项

    sudo apt install --no-install-recommends <package_name>

卸载软件包

  • 卸载软件包但保留配置文件

    sudo apt remove <package_name>
  • 卸载软件包并删除配置文件。如果相关目录不为空,将不会删除,会输出提示

    sudo apt purge <package_name>

    或者

    sudo apt remove --purge <package_name>
  • 清理未使用的依赖包

    当你卸载一个软件包时,它可能会留下一些不再需要的依赖软件包。为了清理这些不再使用的依赖,可以执行:

    sudo apt autoremove

    这个命令会检查并自动删除那些被安装为其他软件包依赖但现在不再被任何已安装软件包需要的软件包。

dpkg

列出系统上已安装的软件包

dpkg -l

查找文件所属的软件包

dpkg -S /path/to/file

APT 仓库管理

APT 通过读取配置文件(主要是 /etc/apt/sources.list/etc/apt/sources.list.d/*.list)来获取软件包仓库(repository)的信息。

APT 的软件源配置文件是 /etc/apt/sources.list ,此外还可以包含 /etc/apt/sources.list.d/ 目录下的 .list 文件。这些文件定义了 APT 从哪里下载软件包和更新信息。

一个典型的 sources.list 条目格式如下:

deb [options] url distribution component1 component2 component3

  • deb:表示这是一个二进制软件包的仓库,对应的 deb-src 表示源代码仓库。
  • options:可选项,例如可以指定架构。
  • url:仓库的 URL。
  • distribution:发行版的代号,如 focalbuster 等。
  • component :仓库中的组成部分,如 mainrestricted 等。

Repository 的类型

在 APT 的上下文中,软件包仓库是网络或本地的存储位置,它们存储了软件包及其元数据。主要有以下几种类型的仓库:

  • Main:官方支持的免费软件。
  • Universe:社区维护的免费软件。
  • Restricted:官方支持的非自由软件。
  • Multiverse:非自由软件,不包括官方支持。

添加新的软件源

要添加新的软件源,你可以直接编辑 sources.list 文件或在 sources.list.d/ 目录下创建一个新的 .list 文件。例如,添加一个新的 PPA(Personal Package Archive):

sudo add-apt-repository ppa:<repository_name>

这个命令不仅会添加软件源,还会自动导入仓库的公钥,确保软件包的安全性。

删除软件源

要删除软件源,可以直接编辑 sources.list 文件或删除 sources.list.d/ 目录下相应的 .list 文件。之后,运行 sudo apt update 来更新软件包列表。

环境信息

  • 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 的负载均衡地址。

<– more –>

admin.conf 的重要性

kubeadm init 初始化集群成功后,会产生一个 kubeconfig 文件 /etc/kubernetes/admin.conf,此配置中包含了一个绑定到 cluster-admin 的 ClusterRole 的组,其拥有对整个集群的控制权,不要将其共享给任何人[3]

kubeadm init 初始化集群成功后,同时会生成一个名为 super-admin.confkubeconfig 文件,其中配置的超级用户可以跳过 authorization layer,比如 RBAC。不要将其共享给任何人。建议将其保存在一个安全的位置。

Node

节点名称

在 Kubernetes 集群中,节点名称(Node Name)唯一的标识一个节点。在一个集群中,不能有多个名称一样的节点,Kubernetes 系统默认同一个 节点名(Node Name) 的实例将具有同样的一个状态和属性 [7]

配置节点为不可调度

将节点标记为 不可调度(unschedulable ) 会阻止系统调度新的 Pod 到节点上,但是不会影响节点上已有的 Pod。

Labels Selectors Annotations

Label 主要用来给 Kubernetes 中的对象添加 可识别属性。 Label 可以提供高效的查询和匹配以选择 Kubernetes 中的对象,Lables 可以在对象创建时或者运行过程中随时做变更。

不具有识别属性的信息 不建议用作 Labels,而是应该写入 Annotations 中。[5]

Label Key 由 2 部分构成:

  • (可选的)前缀。系统组件(如 kube-scheduler, kube-controller-manager, kube-apiserver, kubectl) 或者第三方自动化组件为对象添加 labels 时必须带有前缀(prefix)。kubernetes.io/ and k8s.io/ 是为 Kubernetes 核心系统保留的前缀
  • (必须的)名字。

    Annotations 的 Key 命名规则和 Label Key 基本一致 [6]

Label select 用法说明

集群间通讯流量说明

API Server 到 kubelet

API Server 请求 kubelet 的主要目的包括: [8]

  • 获取到 Pods 的日志
  • (比如使用 kubectl) Attach 到 Pods 中的容器
  • 提供 kubelet 的端口转发功能。

默认情况下,API 服务器不检查 kubelet 的服务证书。这使得此类连接容易受到中间人攻击, 在非受信网络或公开网络上运行也是 不安全的
为了对这个连接进行认证,使用 --kubelet-certificate-authority 标志给 API 服务器提供一个根证书包,用于 kubelet 的服务证书。

API Server 到 nodes, pods 和 services

从 API 服务器到节点、Pod 或服务的连接默认为纯 HTTP 方式,因此既没有认证,也没有加密。 这些连接可通过给 API URL 中的节点、Pod 或服务名称添加前缀 https: 来运行在安全的 HTTPS 连接上。 不过这些连接既不会验证 HTTPS 末端提供的证书,也不会提供客户端证书。 因此,虽然连接是加密的,仍无法提供任何完整性保证。 这些连接 目前还不能安全地 在非受信网络或公共网络上运行。 [8]

Kubernetes 支持使用 SSH tunnels 来加密从 API 到 nodes 的链接(目前已经处于废弃状态,推荐使用 Konnectivity service 替代)。

Leases

Kubernetes 使用 Lease API 来更新 kubelet 发送到 Kubernetes API Server 的心跳信息。Kubernetes 中的每一个节点在 kube-node-lease Namespace 中都有一个 Lease Object。kubelet 向系统上报心跳的过程,就是在更新对应的 Lease Object 的 spec.renewTime 字段,Kubernetes 控制平面会使用这个上报的时间戳来决定节点是否可用 [9]

# kubectl describe lease -n kube-node-lease k8s-admin
Name: k8s-node1
Namespace: kube-node-lease
Labels: <none>
Annotations: <none>
API Version: coordination.k8s.io/v1
Kind: Lease
Metadata:
Creation Timestamp: 2023-09-07T09:54:15Z
Managed Fields:
API Version: coordination.k8s.io/v1
Fields Type: FieldsV1
...
Owner References:
API Version: v1
Kind: Node
Name: k8s-node1
UID: db3dafee-1232-4c07-a1c6-524f86a96fbe
Resource Version: 46696081
UID: 053d9b79-81be-4f3f-801e-09192012c822
Spec:
Holder Identity: k8s-node1
Lease Duration Seconds: 40
Renew Time: 2024-02-03T02:30:11.760176Z
Events: <none>

Leases 也被用来确保 HA 的组件(类似 kube-controller-managerkube-scheduler)在同一时刻只有一个实例提供服务,其他实例处于备用状态 [9]

kubelet

串行和并行拉取镜像

Kubelet 默认(同一个节点)串行的拉取镜像,即同一时间只发送一个拉取镜像的请求到 Registry Server,其他的拉取镜像的请求保持等待,直到当前请求处理完成。多个节点上的镜像拉取请求是隔离的,即不同的节点在同一时间是并行的拉取镜像的。 [10]

如果要配置一个节点上的 Kubelet 并行的拉取镜像,可以在 kubelet 的配置中配置 serializeImagePullsfalse,前提是 Registry Server 和 CRI 支持并行拉取镜像。

Pod

Pod 状态

Pod 的状态字段(status) 是一个 PodStatus Object。其中包含 phase 字段。phase 字段描述/记录了 Pod 在其整个生命周期中所处的阶段 [11]

phase 字段可以有以下值:

Value Description
Pending Kubernetes 集群已经接收到创建 Pod 的请求,并且开始调度到节点、下载容器镜像并启动容器,但是有一个或多个容器还未正常运行
Running Pod 已经被调度到某个节点,并且 Pod 中所有的容器已经被创建,至少其中的一个容器已经处于运行状态或重启中
Succeeded Pod 中所有的容器都已经成功终止,并且不会再被重启
Failed Pod 中所有的容器都被终止,但至少有一个容器终止失败,也就是说,容器要么以非零状态码退出或者是被系统终止
Unknow 因为某些原因,Pod 的状态获取不到。这个经常发生在和 Pod 运行的节点通信异常时

Pod 中的容器的状态

Kubernetes 会跟踪 Pod 中每个容器的状态。一旦通过 Scheduler 将 Pod 分配到某个 Node,Kubernetes 会通过 CRI 创建 Pod 中的容器。

在 Kubernetes 中,容器可以有以下 3 种状态 [11]

Value Description
Waiting 表示容器正在进行必要的操作以正常启动,比如拉取镜像、应用 Secret 数据等。当容器处于此状态时,可以通过 kubectl describe pod 查看输出中对应容器的信息,一般会包含一个 Reason 字段简述 Waiting 的原因
Running 表示容器在正常运行
Terminated 表示容器运行结束或者因为某些原因失败。详细信息可以通过 kubectl describe pod 查看

QoS

Kubernetes 会根据 Pod 定义中的 resource requests and limits 将 Pod 划归到某一个 QoS 类中,Kubernetes 将会根据 QoS 类来决定在节点资源不足的情况下,哪些 Pod 将会被优先驱逐(Evict)。目前存在的 QoS 类主要有以下三个 [12]

QoS Class 说明 被驱逐权重
Guaranteed Pod 中的 每个容器必须定义 CPU & Mem requestlimit,并且 request 的值等于 limit 的值,确保系统会预留定义的资源给 Pod 和其中的容器 最后被驱逐
Burstable Pod 中 至少有一个容器定义了 CPU Mem 的 request。可以不定义 limit如果未定义 limit,默认可以使用节点上所有可用的资源 中间级别
BestEffort 未定义任何 CPU Mem 的 requestlimit 最先被驱逐

Memory QoS 基于系统内核的 cgroup v2 实现 [12]

Pod 中如果有个容器因为 Limit 被 kill,系统只会 kill 掉这一个容器并重启之,不会影响其他容器

脚注

环境信息

  • 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 显示当前版本信息
阅读全文 »

环境信息

  • Centos 7.9.2009
  • docker-ce-19.03.15
  • docker-20.10.9

Docker 安装

docker yum 安装

安装 yum 源,docker官方 centos 安装文档

yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装 docker

yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

docker 离线安装

参考链接下载rpm安装包

wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-19.03.15-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-19.03.15-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.13-3.1.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

安装 docker

yum localinstall -y containerd.io-1.4.13-3.1.el7.x86_64.rpm \
docker-ce-cli-19.03.15-3.el7.x86_64.rpm \
docker-ce-19.03.15-3.el7.x86_64.rpm \
docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

以上 2 条命令可以使用以下 1 条命令完成

yum localinstall -y https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-19.03.15-3.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-19.03.15-3.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.13-3.1.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

启动docker

systemctl enable docker --now
阅读全文 »