L B T

记 录 过 去 的 经 验

GIMP(GNU Image Manipulation Program) 是一个开源的专业的图像处理工具 [1]

常用操作

调整图像大小

调整图像大小参考文档

颜色操作

如何将新加元素的颜色调整为和图片上某个像素颜色完全一致

  1. 选择颜色拾取器工具

    在左侧工具栏中,点击 颜色拾取工具(吸管图标),或快捷键 O 。接着鼠标点击图片上你想匹配的颜色。

  2. 将拾取的颜色用于新内容

    拾色后,GIMP 会自动将该颜色设为 前景色(在工具箱左下角可见)

    如果你是使用:

    • 文字工具 : 输入新文字后,在工具选项中点击 颜色 ,然后点击刚才的前景色。

    • 画笔/填充工具 : 直接使用前景色即可绘制或填充。

复制粘贴

如何将矩形选择工具选择的区域复制粘贴到其他区域

  1. 使用矩形选择工具

    在左侧工具栏选择 矩形选择工具(快捷键:R)。在图像中框选你要复制的区域。

  2. 复制或剪切该区域

    • 复制 :快捷键 Ctrl + C(或 菜单:编辑 > 复制 )。
    • 剪切 (如果你想把原位置清除): Ctrl + X(或 菜单:编辑 > 剪切 )。
  3. 粘贴到新位置

    Ctrl + V (或 菜单:编辑 > 粘贴 )。 此时会出现一个名为 浮动选择(浮动图层) 的新图层,附着在原图上。

  4. 移动

    在左侧工具栏选择 移动工具(十字箭头图标,快捷键:M)。 拖动粘贴的内容到你想要放置的位置。

  5. 锚定或新建图层

    如果你满意现在的位置,可以:

    • 锚定图层Ctrl + H图层 > 锚定图层 ,粘贴内容会并入原图。
    • 转为新图层 :右键 浮动图层 > 转为新图层 ,便于后续调整。

测量图片中元素大小

要测量图片中指定元素的精确大小(Pixel),可以参考以下方法

  • 使用 测量工具(Measure Tool)

    1. 在工具箱中点击 测量工具 (图标像一个圆规),或按快捷键 Shift + M鼠标点击图片上你要测量的起点 → 拖动到终点。状态栏会实时显示 距离(以像素为单位) ,如 Distance: XXX px
  • 使用 矩形选择工具 看宽高

    1. 选择 矩形选择工具 (快捷键 R), 用鼠标拖出一个区域(框住你要测量的元素), 在 工具选项 面板或 状态栏 里,会显示所选区域的
      Position: X, Y
      Size: Width x Height(单位是 px)

抬高图片的某一个角

图片经常会出现某个角较低或较高的情况,此时想要调整图片是所有角处于完美的矩形状态,可以使用 透视工具(Perspective Tool)

  1. 工具箱里面选择 透视工具(Perspective Tool) 或使用快捷键 Shift + P
  2. 图片中会出现四个角,随意拖动四个角,到想要要的位置,点击 变换(Transform) 完成

参考链接

GNU IMAGE MANIPULATION PROGRAM

脚注

  • JPEG - Joint Photographic Experts Group , 图像有损压缩标准 ,主要用于数码图像的存储和传输,

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 时存在不稳定性,建议升级内核版本到新版本

Linux 升级内核
  • 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]

  • Kubernetes v1.32 需要 Linux Kernel >= 4.19, 建议 5.8+ 以更好的支持 cgroups v2

  • Rocky Linux 8 或者 Centos 8 默认使用 cgroup v1,需要升级到 cgroup v2,执行命令 grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1" 后重启即可升级到 cgroup v2 使用以下命令检查:

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

    若 CRI 使用 Containerd,需要 配置启用 CRI 以及配置其使用 cgroup v2

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

环境信息

  • 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

安装 ingress-nginx controller

此文档中的配置主要针对基于部署在裸机(安装通用 Linux 发行版的物理机或者云主机系统)上的 Kebernetes 集群

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.1/deploy/static/provider/cloud/deploy.yaml
mv deploy.yaml ingress-nginx-controller-v1.3.1.yaml

基于 hostNetwork 的 ingress-nginx controller

编辑 ingress-nginx-controllerDeployment 配置文件,在 Deployment 中的 .spec.template.spec 下添加字段 hostNetwork: true,以使 ingress-nginx-controller 可以使用节点的主机网络提供对外访问

阅读全文 »

环境信息

  • Centos7 3.10.0-1160
  • Docker Engine - Community 23.0.3
  • kubernetes 1.21.2-0
  • kubernetes-cni-0.8.7-0

Kubernetes 对任何网络实现都规定了以下要求: [1]

  • 所有 Pod 都可以在不使用网络地址转换 (NAT) 的情况下与所有其他 Pod 通信。

    容器之间直接通信,不需要额外的 NAT,不存在源地址伪装的情况

  • 所有节点都可以在没有 NAT 的情况下与所有 Pod 通信。

    Node 与容器直接通信,不需要额外的 NAT

  • Pod 认为自己的 IP 与其他人认为的 IP 相同。

CNI

CNI 是 Kubernetes 容器网络的标准,CNI 是 Kubernetes 和底层网络插件之间的一个抽象层,为 Kubernetes 屏蔽了底层网络实现的负责度,同时解耦了 Kubernetes 和具体的网络插件实现。

安装 CNI

$ yum install kubernetes-cni

$ rpm -qa | grep kube
kubeadm-1.21.2-0.x86_64
kubectl-1.21.2-0.x86_64
kubelet-1.21.2-0.x86_64
kubernetes-cni-0.8.7-0.x86_64

$ rpm -ql kubernetes-cni-0.8.7-0
/opt/cni
/opt/cni/bin
/opt/cni/bin/bandwidth
/opt/cni/bin/bridge
/opt/cni/bin/dhcp
/opt/cni/bin/firewall
/opt/cni/bin/flannel
/opt/cni/bin/host-device
/opt/cni/bin/host-local
/opt/cni/bin/ipvlan
/opt/cni/bin/loopback
/opt/cni/bin/macvlan
/opt/cni/bin/portmap
/opt/cni/bin/ptp
/opt/cni/bin/sbr
/opt/cni/bin/static
/opt/cni/bin/tuning
/opt/cni/bin/vlan

Kubernetes 要使用 CNI,需要在 kubelet 启动时配置启动参数 --network-plugin=cni(默认配置,可使用 systemctl status kubelet -l 查看启动参数)。

kubelet 从 --cni-config-dir (默认为 /etc/cni/net.d/)中读取网络插件的配置文件,并使用该文件中的 CNI 配置来配置每个 Pod 网络。如果该目录 (/etc/cni/net.d/)中有多个配置文件,则使用文件名字典序列中的第一个文件。

CNI 插件的二进制文件放置的目录是通过 kubelet 的 --cni-bin-dir 参数指定,默认为 /opt/cni/bin/

阅读全文 »

环境信息

  • etcd v3.5

etcd 官网安装指南
Github 下载链接

wget https://github.com/etcd-io/etcd/releases/download/v3.5.9/etcd-v3.5.9-linux-amd64.tar.gz

tar -xf etcd-v3.5.9-linux-amd64.tar.gz -C /usr/local/

ln -s /usr/local/etcd-v3.5.9-linux-amd64/etcd /usr/bin/
ln -s /usr/local/etcd-v3.5.9-linux-amd64/etcdctl /usr/bin/
ln -s /usr/local/etcd-v3.5.9-linux-amd64/etcdutl /usr/bin/

启动 etcd

# etcd
{"level":"warn","ts":"2023-10-05T02:16:52.853273Z","caller":"embed/config.go:673","msg":"Running http and grpc server on single port. This is not recommended for production."}
{"level":"info","ts":"2023-10-05T02:16:52.853914Z","caller":"etcdmain/etcd.go:73","msg":"Running: ","args":["etcd"]}
{"level":"warn","ts":"2023-10-05T02:16:52.853947Z","caller":"etcdmain/etcd.go:105","msg":"'data-dir' was empty; using default","data-dir":"default.etcd"}
{"level":"warn","ts":"2023-10-05T02:16:52.853994Z","caller":"embed/config.go:673","msg":"Running http and grpc server on single port. This is not recommended for production."}
{"level":"info","ts":"2023-10-05T02:16:52.854009Z","caller":"embed/etcd.go:127","msg":"configuring peer listeners","listen-peer-urls":["http://localhost:2380"]}
...

常用管理命令

etcd

查看版本信息

# etcd --version
etcd Version: 3.5.3
Git SHA: 0452feec7
Go Version: go1.16.15
Go OS/Arch: linux/amd64

创建集群

etcd 创建集群涉及参数说明

name 说明 命令行参数
name 每个集群成员的唯一名称 --name=etcd0
initial-advertise-peer-urls 群成员广播给集群其他成员(用于连接本节点)的 URL
默认为 http://IP:2380
--initial-advertise-peer-urls=http://10.0.0.10:2380
listen-peer-urls 在这些(一个或多个) URL 上监听其他集群成员的连接请求
通信包括了集群管理任务、数据同步和心跳检测等
http://10.0.0.10:2380,http://127.0.0.1:2380
listen-client-urls 该成员监听客户端连接的 URL。 默认端口 2379 --listen-client-urls=http://10.0.0.10:2379,http://127.0.0.1:2379
advertise-client-urls 该成员广播给客户端的 URL --advertise-client-urls=http://10.0.0.10:2379
initial-cluster 所有 etcd 成员的初始列表 --initial-cluster=etcd0=http://10.0.0.10:2380,etcd1=http://10.0.0.11:2380,etcd2=http://10.0.0.12:2380
data-dir etcd 数据的存储目录。 --data-dir=/var/lib/etcd
initial-cluster-token 初始集群的唯一标识符,用于区分不同的 etcd 集群 --initial-cluster-token=my-etcd-token
initial-cluster-state 初始集群状态,可以是 newexisting
通常在引导新集群时使用 new,而在添加或删除成员时使用 existing
--initial-cluster-state=new
quota-backend-bytes etcd 的后端数据库大小的硬限制,默认是 2GB --quota-backend-bytes=3000000000
cert-file
key-file
用于 HTTPS 的证书和私钥 --cert-file=/etc/kubernetes/pki/etcd/server.crt
--key-file=/etc/kubernetes/pki/etcd/server.key
trusted-ca-file 客户端和对等体的验证所需的 CA 证书 --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
client-cert-auth 启用客户端证书验证,默认为 false --client-cert-auth

listen-peer-urlsinitial-advertise-peer-urls 的区别说明:

  • listen-peer-urls

    这个参数指定了 etcd 成员应该在哪些地址和端口上监听来自其他 etcd 成员的请求(数据同步、领导选举、集群更改等相关)

    主要用途是定义哪个网络接口和端口号应该被 etcd 服务绑定,以便它可以接收来自其他成员的连接

  • initial-advertise-peer-urls

    这个参数告诉 etcd 该如何 通告自己 给集群中的其他成员。这是其他集群成员用来联系此 etcd 成员的地址。

    主要用途是 当新成员加入集群时,它需要通知其他成员自己的存在,以及如何与自己通信,因此它必须是个其他节点可达的 Endpoints,如 http://0.0.0.0:2380 就不行。

    listen-client-urlsadvertise-client-urls 的区别同理

示例环境说明

主机 IP 角色
etcd1 172.17.0.2/16 etcd node
etcd2 172.17.0.3/16 etcd node
etcd3 172.17.0.4/16 etcd node

分别在 3 个节点上执行以下 3 条命令,创建集群

etcd1 执行命令:

etcd --data-dir=data.etcd --name etcd1 \
--initial-advertise-peer-urls http://172.17.0.2:2380 --listen-peer-urls http://172.17.0.2:2380,http://127.0.0.1:2380 \
--advertise-client-urls http://172.17.0.2:2379 --listen-client-urls http://172.17.0.2:2379,http://127.0.0.1:2379 \
--initial-cluster etcd1=http://172.17.0.2:2380,etcd2=http://172.17.0.3:2380,etcd3=http://172.17.0.4:2380 \
--initial-cluster-state new --initial-cluster-token etcd-cluster

etcd2 执行命令:

etcd --data-dir=data.etcd --name etcd2 \
--initial-advertise-peer-urls http://172.17.0.3:2380 --listen-peer-urls http://172.17.0.3:2380,http://127.0.0.1:2380 \
--advertise-client-urls http://172.17.0.3:2379 --listen-client-urls http://172.17.0.3:2379,http://127.0.0.1:2379 \
--initial-cluster etcd1=http://172.17.0.2:2380,etcd2=http://172.17.0.3:2380,etcd3=http://172.17.0.4:2380 \
--initial-cluster-state new --initial-cluster-token etcd-cluster

etcd3 执行命令:

etcd --data-dir=data.etcd --name etcd3 \
--initial-advertise-peer-urls http://172.17.0.4:2380 --listen-peer-urls http://172.17.0.4:2380,http://127.0.0.1:2380 \
--advertise-client-urls http://172.17.0.4:2379 --listen-client-urls http://172.17.0.4:2379,http://127.0.0.1:2379 \
--initial-cluster etcd1=http://172.17.0.2:2380,etcd2=http://172.17.0.3:2380,etcd3=http://172.17.0.4:2380 \
--initial-cluster-state new --initial-cluster-token etcd-cluster

检查节点健康状态

# ENDPOINT=http://172.17.0.3:2380,http://172.17.0.2:2380,http://172.17.0.4:2380

# etcdctl endpoint status --endpoints=$ENDPOINT -w table
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://172.17.0.3:2380 | 660aa483274d103a | 3.5.9 | 20 kB | false | false | 2 | 9 | 9 | |
| http://172.17.0.2:2380 | 69015be41c714f32 | 3.5.9 | 20 kB | true | false | 2 | 9 | 9 | |
| http://172.17.0.4:2380 | ad0233873e2a0054 | 3.5.9 | 20 kB | false | false | 2 | 9 | 9 | |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

# etcdctl endpoint health --endpoints=$ENDPOINT -w table
+------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+------------------------+--------+------------+-------+
| http://172.17.0.2:2380 | true | 2.44553ms | |
| http://172.17.0.3:2380 | true | 2.804559ms | |
| http://172.17.0.4:2380 | true | 2.580515ms | |
+------------------------+--------+------------+-------+

etcdctl

查看版本信息

# etcdctl version
etcdctl version: 3.5.3
API version: 3.5

etcd 集群管理

查看 etcd 集群成员列表

Kubernetes 中查看 etcd 集群成员列表使用如下命令

# kubectl exec -n kube-system -it etcd-k8s-master1 -- sh -c "ETCDCTL_API=3 etcdctl member list --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key"
3c087bf12db7a0f, started, k8s-master2, https://172.31.30.115:2380, https://172.31.30.115:2379, false
92e04392f8ad0046, started, k8s-master3, https://172.31.29.250:2380, https://172.31.29.250:2379, false
c71592552b3eb9bb, started, k8s-master1, https://172.31.30.123:2380, https://172.31.30.123:2379, false

指定输出格式为 table

# etcdctl member list --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key --write-out=table
+------------------+---------+-------------+----------------------------+----------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-------------+----------------------------+----------------------------+------------+
| 3c087bf12db7a0f | started | k8s-master2 | https://172.31.30.115:2380 | https://172.31.30.115:2379 | false |
| 92e04392f8ad0046 | started | k8s-master3 | https://172.31.29.250:2380 | https://172.31.29.250:2379 | false |
| c71592552b3eb9bb | started | k8s-master1 | https://172.31.30.123:2380 | https://172.31.30.123:2379 | false |
+------------------+---------+-------------+----------------------------+----------------------------+------------+

输出内容说明如下:

  • 3c087bf12db7a0f : 集群中每一个成员的唯一 ID。
  • started : 集群成员的当前状态。started 表示活动的。
  • k8s-master2 : etcd 集群成员的名字,通常与其主机名或节点名相对应
  • https://172.31.30.115:2380 : Peer URLs,其他 etcd 成员用于与该成员通信的 URL。默认为 本地 IP 的 2380 端口
  • https://172.31.30.123:2379 : Client URLs ,客户端用于与 etcd 成员通信的 URL。默认为 本地 IP 的 2379 端口
  • Is Learner : 表示该成员是否是一个 learner。Learner 是 etcd 的一个新功能,允许一个成员作为非投票成员加入集群,直到它准备好成为一个完全参与的成员。false 表示它们都不是 learners

检查集群状态

检查单个节点的集群配置状态

# etcdctl --write-out=table endpoint status --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 127.0.0.1:2379 | c71592552b3eb9bb | 3.5.3 | 106 MB | false | false | 16 | 228198001 | 228198001 | |
+----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

查看所有节点的集群配置状态

# ENDPOINTS=https://172.31.30.115:2379,https://172.31.29.250:2379,https://172.31.30.123:2379

# etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://172.31.30.115:2379 | 3c087bf12db7a0f | 3.5.3 | 106 MB | true | false | 16 | 228199920 | 228199920 | |
| https://172.31.29.250:2379 | 92e04392f8ad0046 | 3.5.3 | 106 MB | false | false | 16 | 228199920 | 228199920 | |
| https://172.31.30.123:2379 | c71592552b3eb9bb | 3.5.3 | 106 MB | false | false | 16 | 228199920 | 228199920 | |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

# etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint health
+----------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+----------------------------+--------+------------+-------+
| https://172.31.30.115:2379 | true | 7.927976ms | |
| https://172.31.30.123:2379 | true | 8.011055ms | |
| https://172.31.29.250:2379 | true | 8.349179ms | |
+----------------------------+--------+------------+-------+
阅读全文 »

适用以下版本

  • Centos 7 内核升级
  • Centos 8 或 Rocky Linux 8 内核升级

环境息息

  • Centos7 3.10.0-1062.9.1.el7.x86_64
  • Rocky Linux 8

升级步骤

安装 centos-kernel

如果是 Centos 7 ,参考以下命令安装 centos-kernel

elrepo-kernel 中已经没有 Centos 7 相关的内核安装包

yum install centos-release

安装 elrepo 源

如果是 Centos 8 或 Rocky Linux 8,参考以下命令安装 elrepo

# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
# rpm --import https://www.elrepo.org/RPM-GPG-KEY-v2-elrepo.org

# yum install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm

# yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
Last metadata expiration check: 0:00:14 ago on Fri 28 Feb 2025 11:42:09 AM HKT.
Available Packages
bpftool.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-core.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-devel.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-doc.noarch 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-headers.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-modules.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-modules-extra.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-tools.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-tools-libs.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-lt-tools-libs-devel.x86_64 5.4.290-1.el8.elrepo elrepo-kernel
kernel-ml.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-core.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-devel.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-doc.noarch 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-headers.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-modules.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-modules-extra.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-tools.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-tools-libs.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
kernel-ml-tools-libs-devel.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
perf.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
python3-perf.x86_64 6.13.5-1.el8.elrepo elrepo-kernel
阅读全文 »

strace 命令示例,详细使用说明请参考 man strace

# strace ls
execve("/usr/bin/ls", ["ls"], 0x7ffe75aa9350 /* 12 vars */) = 0
brk(NULL) = 0x556c51ed9000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffc20fecaf0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2b1b0a2000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=34211, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 34211, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2b1b099000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
...

strace 跟踪输出中包含

  • Syscall Name ,如 execveopenat
  • Arguments , 系统调用使用的参数,如 "/usr/bin/ls"AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC
  • Return Value ,系统调用的返回值以及简要说明信息, 如 = -1 EINVAL (Invalid argument)-1 ENOENT (No such file or directory)= 0

strace 命令常用选项

选项 说明 示例
-o filename
--output=filename
将跟踪内容写入指定文件而不是 STDOUT(默认值)
-p pid
--attach=pid
追踪 PIDs 对应的进程,Ctrl + C 结束追踪。 支持 , 、 空格 ( ) 、 TAB 键( \t )分割的多个 PID
-e expr 追踪表达式匹配的系统调用,表达式语法请参考 man strace
-c
--summary-only
仅输出调用的统计数据,不输出常规跟踪内容
-C
--summary
输出常规跟踪内容后,输出统计信息

环境信息

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

安装

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

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

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

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

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

# python --version
Python 3.12.3

# pip install ansible

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

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

Ansible 配置说明

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

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

常用配置说明

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

配置示例

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

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

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

Inventory 配置说明

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

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

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

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

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

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

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

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

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

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

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

Inventory 多配置文件支持

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

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

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

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

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

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

INI 格式的 Inventory

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

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

[webserver]
webserver1.local
webserver2.local

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


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

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

环境信息

  • Centos 7
  • containerd.io-1.4.13-3

containerd 相关配置

默认配置文件

containerd 服务默认配置文件为 /etc/containerd/config.toml

/etc/containerd/config.toml
#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

Containerd 有两个不同的存储路径,一个用来保存持久化数据,一个用来保存运行时状态。 [1]

/etc/containerd/config.toml
#root = "/var/lib/containerd"
#state = "/run/containerd"
  • root - 用来保存持久化数据,包括 Snapshots, Content, Metadata 以及各种插件的数据。每一个插件都有自己单独的目录,Containerd 本身不存储任何数据,它的所有功能都来自于已加载的插件。
  • state - 用来保存临时数据,包括 socketspid挂载点运行时状态 以及不需要持久化保存的插件数据。
/etc/containerd/config.toml
#oom_score = 0

Containerd 是容器的守护者,一旦发生内存不足的情况,理想的情况应该是先杀死容器,而不是杀死 Containerd。所以需要调整 Containerd 的 OOM 权重,减少其被 OOM Kill 的几率。oom_score 其取值范围为 -10001000,如果将该值设置为 -1000,则进程永远不会被杀死,建议 Containerd 将该值设置为 -9990 之间。如果作为 Kubernetes 的 Worker 节点,可以考虑设置为 -999

containerd 服务配置文件

默认的 containerd 服务的配置为 /usr/lib/systemd/system/containerd.service

/usr/lib/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5

LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576

TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target

  • Delegate - 这个选项允许 Containerd 以及运行时自己管理自己创建的容器的 cgroups。如果不设置这个选项,systemd 就会将进程移到自己的 cgroups 中,从而导致 Containerd 无法正确获取容器的资源使用情况。

  • KillMode - 这个选项用来处理 Containerd 进程被杀死的方式。默认情况下,systemd 会在进程的 cgroup 中查找并杀死 Containerd 的所有子进程,这肯定不是我们想要的。KillMode 字段可以设置的值如下:

    • control-group -(默认值)当前控制组里面的所有子进程,都会被杀掉
    • process - 只杀主进程。
    • mixed - 主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号
    • none - 没有进程会被杀掉,只是执行服务的 stop 命令。

    需要将 KillMode 的值设置为 process,这样可以确保升级或重启 Containerd 时不杀死现有的容器。

Containerd 常用配置

Containerd 默认配置文件为 /etc/containerd/config.toml,未在配置文件中配置的则使用默认配置,为了方便修改,可以使用以下命令将默认配置写入配置文件中

/etc/containerd/config.toml
containerd config default | sudo tee /etc/containerd/config.toml

在作为 Kubernetes 的 CRI 时,需要修改以下配置:

  • 启用 CRI 功能 。Containerd 默认禁用了 CRI 功能(disabled_plugins = ['cri']),要启用 cri ,将其注释或删除
  • 配置 cgroup v2 Kubernetes 的很多功能需要 cgroup v2 支持,Kubernetes 节点通常使用 cgroup v2,要配置 containerd 使用 cgroup v2,修改配置文件的 plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options 部分,将 SystemdCgroup 配置为 true 后重启 containerd 服务
    /etc/containerd/config.toml
    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    BinaryName = ""
    CriuImagePath = ""
    CriuPath = ""
    CriuWorkPath = ""
    IoGid = 0
    IoUid = 0
    NoNewKeyring = false
    NoPivotRoot = false
    Root = ""
    ShimCgroup = ""
    SystemdCgroup = true

客户端工具 ctr 使用

ctr 管理镜像

镜像下载

ctr image pull docker.io/library/nginx:alpine

列出本地镜像

$ ctr image ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:455c39afebd4d98ef26dd70284aa86e6810b0485af5f4f222b19b89758cabf1e 9.8 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -

将镜像挂载到本地目录

$ ctr image mount docker.io/library/nginx:alpine /mnt

$ ls /mnt
bin docker-entrypoint.d etc lib mnt proc run srv tmp var
dev docker-entrypoint.sh home media opt root sbin sys usr

卸载已挂载的镜像

ctr image unmount /mnt

ctr 管理 容器

创建容器

ctr container create docker.io/library/nginx:alpine nginx

容器创建后,并没有开始运行,只是分配了容器运行所需的资源及配置的数据结构,这意味着 namespacesrootfs 和容器的配置都已经初始化成功了,只是用户进程(这里是 nginx)还没有启动,容器(进程)状态的变化由 Task 对象实现,通过命令 ctr task 来管理。

启动 ctr container create 创建的容器

ctr task start nginx

以上命令启动之前创建的容器 nginx,未指定其他参数时,容器中的进程在系统前台运行,如需后台运行,可以使用选项 -d

ctr task start nginx -d

也可以直接使用 run 命令,创建并启动容器

ctr run --rm -d docker.io/library/nginx:alpine nginx1

列出容器

ctr container ls

查看容器中进程的状态

$ ctr task ls
TASK PID STATUS
nginx1 5495 RUNNING

查看容器中运行的所有的进程

$ ctr task ps nginx1
PID INFO
5495 -
5531 -
5532 -
5533 -
5534 -

这里的 PID 是宿主机看到的 PID,不是容器中看到的 PID。

查看容器详细信息

ctr container info nginx

删除容器

停止/删除容器中的进程

ctr task delete nginx -f

ctr task pause nginx

以上命令删除/停止容器中的进程,但是并不删除容器,执行以上命令后再执行以下命令,可删除容器

ctr container delete nginx

ctr 没有 stop 容器的功能,只能暂停或者杀死容器。

进入容器

ctr task exec -t --exec-id 1 nginx1 sh

执行 ctr task exec 进入容器,必须制定 --exec-id,值可以随便指定。

namespace 管理

Containerd 相比于 Docker ,多了 Namespace 的概念,使用以下命令,查看所有的 Namespace

$ ctr ns ls
NAME LABELS
default
moby

docker 默认使用 moby 的 Namespace,要使用 ctr 命令查看 docker 创建的容器,需要使用选项 -n moby 指定命名空间,否则 ctr 默认使用 default 命名空间,无法看到 moby 命名空间中的资源

ctr -n moby container ls
CONTAINER IMAGE RUNTIME
17b16c3699cdb88a1ff80d8a7c84724eff393c42186775b58418c90bd178600f - io.containerd.runtime.v1.linux
27fc19226baa91251d63a375a7b1309122334cfb5ceb39aeb67ab1701b708464 - io.containerd.runtime.v1.linux

Kubernetes 默认使用 k8s.io 命名空间

ctr 没有配置或者环境变量可以来配置默认的 Namespace,在 Kubernetes 场景中,可以使用 alias 命令配置 ctr,使其自动指向 k8s.io 的 Namespace

alias ctr='ctr -n k8s.io'

nerdctl

nerdctl 是为 Containerd 开发的完全兼容 Docker 命令行的工具,它可以使用和 docker 命令一样的语法来操作 containerd 中的容器。

nerdctl 官方说明文档

如果要使用 nerdctl 调试 Kubernetes 环境中的容器,需要指定 Namespace,示例如下:

# nerdctl --namespace k8s.io ps -a

如果是在 Kubernetes 环境中使用,为方便起见,可以添加环境变量:

# alias nerdctl='nerdctl --namespace k8s.io'

# nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4de4c59a8913 registry.k8s.io/kube-controller-manager:v1.32.0 "kube-controller-man…" 2 days ago Up k8s://kube-system/kube-controller-manager-k8s-master/kube-controller-manager
6a9f17dffdb5 registry.k8s.io/pause:3.6 "/pause" 2 days ago Up k8s://kube-system/kube-controller-manager-k8s-master
3ae8ed830b63 registry.k8s.io/kube-scheduler:v1.32.0 "kube-scheduler --au…" 2 days ago Up k8s://kube-system/kube-scheduler-k8s-master/kube-scheduler
0cb15e8f5ac7 registry.k8s.io/pause:3.6 "/pause" 2 days ago Up k8s://kube-system/kube-scheduler-k8s-master
60ea2cfc01c8 registry.k8s.io/pause:3.6 "/pause" 2 days ago Up k8s://kube-system/kube-apiserver-k8s-master
eaf781314f4a registry.k8s.io/pause:3.6 "/pause" 2 days ago Up k8s://kube-system/etcd-k8s-master

脚注

nftables 是一个 netfilter 项目,旨在替换现有的 {ip,ip6,arp,eb}tables 框架,为 {ip,ip6}tables 提供一个新的包过滤框架、一个新的用户空间实用程序(nft)和一个兼容层(iptables-nft)。它使用现有的钩子、链接跟踪系统、用户空间排队组件和 netfilter 日志子系统。

在 Linux 内核版本高于 3.13 时可用

它由三个主要组件组成:

  • 内核实现: 内核提供了一个 netlink 配置接口以及运行时规则集评估
  • libnl netlink : libnl 包含了与内核通信的基本函数
  • nftables : 用户空间前端。nftables 的用户空间实用程序 nft 评估大多数规则集并传递到内核。规则存储在链中,链存储在表中。

iptables 不同点

  • nftables 在用户空间中运行,iptables 中的每个模块都运行在内核(空间)中
  • 表和链是完全可配置的。在 nftables 中,表是没有特定语义的链的容器。iptables 附带了具有预定义数量的基链的表,即使您只需要其中之一,所有链都已注册,未使用的基础链也会损害性能。
  • 可以在一个规则中指定多个操作。在 iptables 中,您只能指定一个目标。这是一个长期存在的局限性,用户可以通过跳到自定义链来解决,但代价是使规则集结构稍微复杂一些。
  • 每个链和规则没有内置计数器。在 nftables 中,这些是可选的,因此您可以按需启用计数器。由于 iptables 内置了一个数据包计数器,所以即使这些内置的链是空的,也会带来性能损耗
  • 更好地支持动态规则集更新。在 nftables 中,如果添加新规则,则剩余的现有规则将保持不变,因为规则集以链表形式表示,这与整体式 blob 表示相反,后者在执行规则集更新时内部状态信息的维护很复杂。
  • 简化的双堆栈 IPv4/IPv6 管理,通过新的 inet 系列,可让您注册同时查看 IPv4 和 IPv6 流量的基链。 因此,您不再需要依赖脚本来复制规则集。

服务名称默认为 nftables,默认配置文件为 /etc/nftables.conf ,其中已经包含一个名为 inet filter 的简单 ipv4/ipv6 防火墙列表。

/etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
chain input {
type filter hook input priority 0;
}
chain forward {
type filter hook forward priority 0;
}
chain output {
type filter hook output priority 0;
}
}

nftables 服务的 systemd 配置文件如下:

/lib/systemd/system/nftables.service
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
Wants=network-pre.target
Before=network-pre.target shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft -f /etc/nftables.conf
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
ExecStop=/usr/sbin/nft flush ruleset

[Install]
WantedBy=sysinit.target

nftables 使用的内核模块如下,加载这些模块,服务才能正常运行

# lsmod | grep nf
nf_log_syslog 20480 1
nft_chain_nat 16384 17
nf_nat 49152 3 xt_nat,nft_chain_nat,xt_MASQUERADE
nf_conntrack_netlink 49152 0
nft_counter 16384 142
nf_reject_ipv4 16384 1 ipt_REJECT
nf_conntrack 172032 6 xt_conntrack,nf_nat,xt_state,xt_nat,nf_conntrack_netlink,xt_MASQUERADE
nf_defrag_ipv6 24576 1 nf_conntrack
nf_defrag_ipv4 16384 1 nf_conntrack
nft_compat 20480 143
nf_tables 249856 570 nft_compat,nft_counter,nft_chain_nat
nfnetlink 20480 5 nft_compat,nf_conntrack_netlink,nf_tables,ip_set
阅读全文 »

环境信息

  • 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

POD 状态异常

CrashLoopBackOff

错误场景

Pod 状态显示 CrashLoopBackOff

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
test-centos7-7cc5dc6987-jz486 0/1 CrashLoopBackOff 8 (111s ago) 17m

查看 Pod 详细信息

$ kubectl describe pod test-centos7-7cc5dc6987-jz486
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 18m default-scheduler Successfully assigned default/test-centos7-7cc5dc6987-jz486 to ops-kubernetes3
Normal Pulled 16m (x5 over 18m) kubelet Container image "centos:centos7.9.2009" already present on machine
Normal Created 16m (x5 over 18m) kubelet Created container centos7
Normal Started 16m (x5 over 18m) kubelet Started container centos7
Warning BackOff 3m3s (x71 over 18m) kubelet Back-off restarting failed container

结果显示,ReasonBackOffMessage 显示 Back-off restarting failed container

可能原因

Back-off restarting failed container 的原因,通常是因为,容器内 PID 为 1 的进程退出导致(通常用户在构建镜像执行 CMD 时,启动的程序,均是 PID 为1)[1]

容器进程退出(命令执行结束或者进程异常结束),则容器生命周期结束。kubernetes 控制器检查到容器退出,会持续重启容器。针对此种情况,需要检查镜像,是否不存在常驻进程,或者常驻进程异常。

针对此种情况,可以单独使用 docker 客户端部署镜像,查看镜像的运行情况,如果部署后,容器中的进程立马结束或退出,则容器也会随之结束。

定位中也可以使用 kubectl describe pod 命令检查 Pod 的退出状态码。Kubernetes 中的 Pod ExitCode 状态码是容器退出时返回的退出状态码,这个状态码通常用来指示容器的执行结果,以便 Kubernetes 和相关工具可以根据它来采取后续的操作。以下是一些常见的 ExitCode 状态码说明:

  • ExitCode 0 : 这表示容器正常退出,没有错误。这通常是期望的结果。
  • ExitCode 1 : 通常表示容器以非正常方式退出,可能是由于应用程序内部错误或异常导致的。通常是容器中 pid 为 1 的进程错误而失败
  • ExitCode 非零 : 任何非零的状态码都表示容器退出时发生了错误。ExitCode 的具体值通常是自定义的,容器内的应用程序可以根据需要返回不同的状态码来表示不同的错误情况。你需要查看容器内应用程序的文档或日志来了解具体的含义。
  • ExitCode 137 : 通常表示容器因为被操作系统终止(例如,OOM-killer)而非正常退出。这可能是由于内存不足等资源问题导致的。
  • ExitCode 139 : 通常表示容器因为接收到了一个信号而非正常退出。这个信号通常是 SIGSEGV(段错误),表示应用程序试图访问无效的内存。
  • ExitCode 143 : 通常表示容器因为接收到了 SIGTERM 信号而正常退出。这是 Kubernetes 在删除 Pod 时发送的信号,容器应该在接收到该信号后做一些清理工作然后退出。
  • ExitCode 130 : 通常表示容器因为接收到了 SIGINT 信号而正常退出。这是当用户在命令行中按下 Ctrl+C 时发送的信号。
  • ExitCode 255 :通常表示未知错误,或者容器无法启动。这个状态码通常是容器运行时的问题,比如容器镜像不存在或者启动命令有问题。
阅读全文 »

PAT 认证

Github 为了安全考虑,在 Shell 中禁止使用帐号名称登陆,提供了更为安全的 PAT(Personal Access Token),PAT 的权限和创建它的用户权限相同,并且可以使用 Fine-grained personal access tokens 实现更细粒度的权限控制

参考以下步骤创建 PAT:

  1. 登录 GitHub。

  2. 点击右上角头像,进入 Settings

  3. 在左侧菜单中选择 Developer settings

  4. 选择 Personal access tokens ,然后点击 Generate new token

  5. 生成令牌并复制。

gh

Github 命令行工具 gh 常用操作

Login

参考以下示例使用命令 gh auth login 登陆 Github

# gh auth login
? Where do you use GitHub? GitHub.com
? What is your preferred protocol for Git operations on this host? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Paste an authentication token
Tip: you can generate a Personal Access Token here https://github.com/settings/tokens
The minimum required scopes are 'repo', 'read:org', 'workflow'.
? Paste your authentication token: *********************************************************************************************
- gh config set -h github.com git_protocol https
✓ Configured git protocol
! Authentication credentials saved in plain text
✓ Logged in as user1

查看 Github 认证状态(gh auth status

# gh auth status
github.com
✓ Logged in to github.com account user1 (/root/.config/gh/hosts.yml)
- Active account: true
- Git operations protocol: https
- Token: github_pat_11BP5YWMA0XuC4iSW26eBN_***********************************************************

pull

参考以下示例使用命令 gh repo clone user1/resp1 clone 代码到本地

# gh repo clone user1/resp1
Cloning into 'resp1'...
remote: Enumerating objects: 27, done.
remote: Counting objects: 100% (27/27), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 27 (delta 12), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (27/27), 9.10 KiB | 9.10 MiB/s, done.
Resolving deltas: 100% (12/12), done.

如果报错: GraphQL: Resource not accessible by personal access token (repository.defaultBranchRef) ,则说明 PAT 权限不足。

环境信息

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

Docker 安装

yum 安装 docker

安装 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

yum 离线安装 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 26 安装,适用于 Centos 8Rocky Linux 8

yum localinstall -y https://download.docker.com/linux/centos/8/x86_64/stable/Packages/docker-ce-26.1.3-1.el8.x86_64.rpm https://download.docker.com/linux/centos/8/x86_64/stable/Packages/docker-ce-cli-26.1.3-1.el8.x86_64.rpm https://download.docker.com/linux/centos/8/x86_64/stable/Packages/containerd.io-1.6.32-3.1.el8.x86_64.rpm https://download.docker.com/linux/centos/8/x86_64/stable/Packages/docker-compose-plugin-2.6.0-3.el8.x86_64.rpm

启动docker

systemctl enable docker --now
阅读全文 »

环境信息

  • Centos 7

vim 配置

vim 启动时会读取 /etc/vimrc(全局配置) 和 ~/.vimrc (用户配置)

常用配置如下,使用 " 注释

/etc/vimrc
" 自动缩进 
set ai
set autoindent

" 保存历史命令数量
set history=50

" 右下角显示当前鼠标位置(行列数)
set ruler

" 鼠标位置所在行显示下划线
set cursorline

" 开启语法高亮
syntax on

" 高亮搜索结果
set hlsearch

" 搜索时不区分大小写
set ignorecase

" 将 tab 转换为空格
set expandtab

" tab 转换为4个空格
set tabstop=4

" 删除时,可以一次删除4个空格
set softtabstop=4

" 显示行数
set nu

" 禁用格式化指令。
set paste
阅读全文 »

环境信息

  • Centos 7 5.4.239-1

Linux 的 namespace 的作用是 隔离内核资 ,目前主要实现了以下 namespace

  • mount namespace - 文件系统挂载点
  • UTS namespace - 主机名
  • IPC namespace - POSIX 进程间通信消息队列
  • PID namespace - 进程 pid 数字空间
  • network namespace - network
  • user namespace - user ID 数字空间
  • cgroup - 资源使用控制
  • time - 隔离时钟(Clock)

其中,除了 network namespace,其他 namespace 的操作需要使用 C 语言调用系统 API 实现。network namespace 的增删改查功能已经集成到了 Linux 的 ip 工具集的 netns 子命令中

Linux 里面的 namespace 给处在其中的进程造成 2 个错觉:

  1. 它是系统里面唯一的进程
  2. 它独享系统的所有资源

默认情况下,Linux 里面的所有进程处在和宿主机相同的 namespace ,即初始 namespace 里,默认享有全局系统资源。

lsns 命令可以查看当前系统上存在哪些 Namespace

# lsns
NS TYPE NPROCS PID USER COMMAND
4026531834 time 251 1 root /lib/systemd/systemd --system --deserialize 52
4026531835 cgroup 224 1 root /lib/systemd/systemd --system --deserialize 52
4026531836 pid 224 1 root /lib/systemd/systemd --system --deserialize 52
4026531837 user 686 1 root /lib/systemd/systemd --system --deserialize 52
4026531838 uts 221 1 root /lib/systemd/systemd --system --deserialize 52
4026531839 ipc 224 1 root /lib/systemd/systemd --system --deserialize 52
4026531840 net 229 1 root /lib/systemd/systemd --system --deserialize 52
4026531841 mnt 213 1 root /lib/systemd/systemd --system --deserialize 52
4026531862 mnt 1 61 root kdevtmpfs
4026532219 mnt 1 1426338 root /lib/systemd/systemd-udevd
4026532220 uts 1 1426338 root /lib/systemd/systemd-udevd
4026532230 mnt 1 2124756 root /lib/systemd/systemd-logind
4026532231 uts 1 2124756 root /lib/systemd/systemd-logind
4026532232 mnt 1 1426274 systemd-timesync /lib/systemd/systemd-timesyncd
4026532233 mnt 1 1426257 root /usr/sbin/irqbalance --foreground
4026532326 mnt 1 2134793 root /usr/sbin/NetworkManager --no-daemon
4026532593 cgroup 7 937225 root python manage.py runserver 0.0.0.0:8080
4026532603 mnt 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532604 uts 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532605 ipc 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532606 pid 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532607 net 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532664 cgroup 1 1416468 472 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:defau
4026532665 mnt 1 1416534 1001 /opt/bitnami/blackbox-exporter/bin/blackbox_exporter --config.file=/etc/blackbox/blackbox.yml
4026532666 uts 1 1416534 1001 /opt/bitnami/blackbox-exporter/bin/blackbox_exporter --config.file=/etc/blackbox/blackbox.yml
4026532667 ipc 1 1416534 1001 /opt/bitnami/blackbox-exporter/bin/blackbox_exporter --config.file=/etc/blackbox/blackbox.yml
4026532668 pid 1 1416534 1001 /opt/bitnami/blackbox-exporter/bin/blackbox_exporter --config.file=/etc/blackbox/blackbox.yml
4026532669 net 1 1416534 1001 /opt/bitnami/blackbox-exporter/bin/blackbox_exporter --config.file=/etc/blackbox/blackbox.yml

想要查看某个进程都在哪些 namespace 中,可以找到进程 ID (PID),通过查看以下内容或者 namespace 信息

$ ps -elf | grep nginx
4 S root 32679 32659 0 80 0 - 2248 sigsus Apr07 ? 00:00:00 nginx: master process nginx -g daemon off;

$ ll /proc/32679/ns/
total 0
lrwxrwxrwx 1 root root 0 Apr 19 13:51 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 ipc -> ipc:[4026534784]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 mnt -> mnt:[4026534583]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 net -> net:[4026534787]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 pid -> pid:[4026534878]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 pid_for_children -> pid:[4026534878]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 uts -> uts:[4026534877]

通过以上命令,可以看到 nginx 进程所属的 namespace,要查看系统初始 namespace ,可以查看 PID 为 1 的进程的 namespace 信息

$ ll /proc/1/ns/
total 0
lrwxrwxrwx 1 root root 0 Apr 19 13:53 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 net -> net:[4026531992]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 uts -> uts:[4026531838]

链接文件的内容的格式为 ns 类型: [inode number]。这里的 inode number 则用来标识一个 namespace,我们也可以把它理解为 namespace 的 ID。如果两个进程的某个 namespace 文件指向同一个链接文件,说明其相关资源在同一个 namespace 中。 [1]

脚注

环境信息

  • Centos 7 kernel 5.4.221

启动过程

systemd 管理的系统中,提供了工具 systemd-analyze 用于分析具体的启动过程,使用 systemd-analyze --help 查看使用帮助

检查系统启动时间

使用 systemd-analyze 命令会显示系统启动所用的时间,等同于 systemd-analyze time

# systemd-analyze 
Startup finished in 1.830s (kernel) + 36.827s (userspace) = 38.657s
graphical.target reached after 12.604s in userspace

systemd-analyze blame 列出系统上各个 Unit 启动的时间

# systemd-analyze blame
6.414s wazuh-agent.service
3.161s dracut-initqueue.service
2.473s network.service
1.004s watchdog.service
...
45ms sysstat.service
14ms plymouth-switch-root.service
14ms systemd-journald.service
4ms systemd-logind.service
3ms sys-kernel-config.mount
3ms initrd-udevadm-cleanup-db.service
3ms systemd-random-seed.service
2ms google-shutdown-scripts.service

列出系统各个 Unit 启动消耗的时间

# systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @12.604s
└─multi-user.target @12.601s
└─skylight-agent.service @36.639s
└─network.target @9.073s
└─NetworkManager.service @8.795s +275ms
└─dbus.service @8.788s
└─basic.target @8.774s
└─sockets.target @8.772s
└─snapd.socket @8.766s +5ms
└─sysinit.target @8.669s
└─cloud-init.service @6.850s +1.811s
└─systemd-networkd-wait-online.service @4.970s +1.871s
└─systemd-networkd.service @4.864s +91ms
└─network-pre.target @4.850s
└─cloud-init-local.service @3.228s +1.620s
└─systemd-remount-fs.service @1.113s +93ms
└─systemd-fsck-root.service @1.030s +69ms
└─systemd-journald.socket @853ms
└─-.mount @692ms
└─-.slice @692ms

查看内存信息

内存相关概念说明:

  • VSS ,Virtual Set Size , VIRT - 虚拟耗用内存(包含共享库占用的内存), 通常 VIRT 是系统承诺分配给应用的内存,不是实际使用的内存
  • RSS , Resident Set Size , RES - 实际使用物理内存(包含共享库占用的内存)
  • PSS , Proportional Set Size - 实际使用的物理内存(比例分配共享库占用的内存)。 top 命令中的 SHR 列展示的就是共享库按比例分配给进程的内存
  • USS , Unique Set Size - 进程独自占用的物理内存(不包含共享库占用的内存)

系统内存使用量统计

free

$ free -h
total used free shared buff/cache available
Mem: 15Gi 7.8Gi 707Mi 449Mi 7.0Gi 6.9Gi
Swap: 30Gi 1.0Gi 29Gi

ps

例如查看使用内存排名前十的进程:

ps aux | sort -k4,4nr | head -n 10

sar 命令

使用 sar 命令检查系统上的内存及 Swap 使用情况

查看某个进程使用的内存量

比如检查 docker 使用的内存量,首先通过 ps 命令查询到 docker 的 PID 信息

$ ps -elf | grep docker
4 S root 1243 1 4 80 0 - 1067527 futex_ Jan03 ? 15:14:45 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

例如此处的 docker 进程的 PID 为 1243

  • 使用 top 命令动态查看 docker 使用的内存信息

    $ top -p 1243
    top - 11:47:40 up 14 days, 2:09, 3 users, load average: 0.65, 1.42, 1.70
    Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
    %Cpu(s): 1.0 us, 0.6 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    KiB Mem : 32068748 total, 2494500 free, 18536188 used, 11038060 buff/cache
    KiB Swap: 0 total, 0 free, 0 used. 9586340 avail Mem

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
    1243 root 20 0 4270108 1.4g 53956 S 1.0 4.6 914:55.80 dockerd
  • 使用 ps aux 命令查看内存使用量

    $ ps aux | grep 1243
    root 1243 4.5 4.6 4270108 1486460 ? Ssl Jan03 914:57 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

    输出结果中

    • 第 3、4 列 (4.5 4.6) 分别表示 cpu 使用率内存使用率
    • 第 5、6 列 (4270108 1486460) 分别表示 虚拟内存使用量物理内存使用量,单位为 k
  • 通过进程的 status 文件查看内存使用

    $ cat /proc/1243/status
    Name: dockerd
    Umask: 0022
    State: S (sleeping)
    Pid: 1243
    PPid: 1
    VmPeak: 4270364 kB
    VmSize: 4270108 kB
    VmLck: 0 kB
    VmPin: 0 kB
    VmHWM: 1562204 kB
    VmRSS: 1492340 kB
    ...

    其中,VmRSS 为进程使用的物理内存

  • 使用 pmap 命令查看进程使用的内存信息

    pmap -x 1243
    pmap -p 1243
  • 使用 pidstat 命令查看进程使用的内存信息

    # pidstat -r -t -p 1424681 1 1
    Linux 6.8.0-1017-aws (U-3TSDMAL9IVFAQ) 11/26/2024 _x86_64_ (4 CPU)

    04:15:40 PM UID TGID TID minflt/s majflt/s VSZ RSS %MEM Command
    04:15:41 PM 408001114 1424681 - 0.00 0.00 34656400 256620 1.59 chrome
    04:15:41 PM 408001114 - 1424681 0.00 0.00 34656400 256620 1.59 |__chrome
    04:15:41 PM 408001114 - 1424696 0.00 0.00 34656400 256620 1.59 |__sandbox_ipc_thr
    04:15:41 PM 408001114 - 1424702 0.00 0.00 34656400 256620 1.59 |__chrome
    04:15:41 PM 408001114 - 1424703 0.00 0.00 34656400 256620 1.59 |__HangWatcher
    04:15:41 PM 408001114 - 1424704 0.00 0.00 34656400 256620 1.59 |__ThreadPoolServi
    04:15:41 PM 408001114 - 1424705 0.00 0.00 34656400 256620 1.59 |__ThreadPoolForeg
    04:15:41 PM 408001114 - 1424706 0.00 0.00 34656400 256620 1.59 |__ThreadPoolForeg

    阅读全文 »

环境信息

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

Ansible Playbook 语法

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

每一个 play 中包含了一个 tasks 列表,tasks 列表中的每个 task 在其对应的 hosts依次执行即一个 task 执行完毕,下一个 task 才会执行

在运行 playbook 的过程中,如果一个 host 执行 task 失败,这个 host 将从整个 playbook 中移除。如果发生执行失败的情况,需要修正 playbook 中的错误,重新执行。

Ansible playbook 示例:

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

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

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

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

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

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

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

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

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

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

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

执行以下命令运行 playbook.yml

ansible-playbook playbook.yml -f 10

常用选项说明

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

环境信息

  • Centos 7

sudo 可以配置适当的权限授予普通用户,使普通用户执行 root 用户才能执行的操作

配置 sudo 权限的主要配置文件为 /etc/sudoers/etc/sudoers是一个只读文件,不能直接使用 vim 等编辑器来编辑,要修改此文件,需要以 root 用户身份使用 visudo 命令来修改。

主要配置文件内容如下

/etc/sudoers
## Allow root to run any commands anywhere
root ALL=(ALL) ALL

%wheel ALL=(ALL) NOPASSWD: ALL

各列值含义说明:

  • root 第一列为用户名,如 rootusers%wheel% 开头表示这是一个组,而不是用户
  • ALL=(ALL) 第二列等号左边的 ALL 表示允许从任何主机登录当前的用户账户;等号右边的 ALL 表示第一列的用户可以切换成系统中任何一个其它用户(如:su users);
  • ALL 第三列表示第一列的用户能下达的命令,ALL 表示可以下达任何命令。NOPASSWD: ALL 意味着成员可以执行指定的命令而无需输入密码。

当我们以普通用户身份(以 test 为例)登录,在使用 sudo 命令时报出如下信息:

test is not in the sudoers file. This incident will be reported.

则说明该用户没有在 /etc/sudoers 文件中进行配置,因此无法使用 sudo 命令

AWS 的 Centos 镜像部署后的虚拟机默认使用 centos 用户登陆,登陆后即可执行 sudo su - 切换到 root 用户,此配置由 /etc/sudoers.d/90-cloud-init-users 配置,内容如下:

/etc/sudoers.d/90-cloud-init-users
# cat /etc/sudoers.d/90-cloud-init-users
# Created by cloud-init v. 19.4 on Mon, 31 Oct 2022 07:58:58 +0000

# User rules for centos
centos ALL=(ALL) NOPASSWD:ALL

若要禁止此行为,删除此文件即可。

使用示例

限制特定用户只能执行指定目录下的脚本

visudo 中,你可以使用 Cmnd_Alias 限制用户只能执行特定目录下的脚本。假设你想让用户 centos 只能执行 /usr/local/scripts/ 目录下的脚本,可以按照以下方式配置:

visudo
Cmnd_Alias ALLOWED_SCRIPTS = /usr/local/scripts/*

centos ALL=(ALL) NOPASSWD: ALLOWED_SCRIPTS

含义

  • Cmnd_Alias ALLOWED_SCRIPTS = /usr/local/scripts/*

    定义 ALLOWED_SCRIPTS ,表示 允许执行 /usr/local/scripts/ 目录下的所有脚本

  • qqc ALL=(ALL) NOPASSWD: ALLOWED_SCRIPTS

    允许 centos 用户以 sudo 执行 ALLOWED_SCRIPTS 目录下的所有脚本,且无需输入密码。

切换到 centos 用户,并尝试执行:

sudo /usr/local/scripts/test.sh

成功执行 ,说明规则生效。

但是,如果 centos 用户 试图运行 /bin/bash/usr/bin/python ,或者访问其他路径

$ sudo /bin/bash
Sorry, user centos is not allowed to execute '/bin/bash' as root on this host.

如果希望 centos 用户可以查看自己可以运行的命令:

visudo
Cmnd_Alias ALLOWED_SCRIPTS = /usr/local/scripts/*
qqc ALL=(ALL) NOPASSWD: ALLOWED_SCRIPTS, /usr/bin/sudo -l

这样,centos 用户可以运行:

sudo -l

来查看自己被允许的 sudo 命令。

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;
}


阅读全文 »