在 Linux 中，你可以根据自己的需要创建高级网络设置，如 网络绑定 Network Bonding 或 网卡聚合 NIC teaming 、VLAN 标记和桥接。这些高级功能可以提高网络连接的效率和可靠性。你可以在以太网、绑定、聚合或桥接设备等其他接口上创建 VLAN 接口。在本文中，我们将学习如何在 RHEL 系统中通过网络绑定配置 VLAN 标记，它允许来自不同网络的流量共享共同的物理链接。通过绑定对 VLAN 进行标记的先决条件网络聚合需要在网络交换机端口上启用 LACP（802.3ad），以聚合链路。网络聚合需要将网络端口配置为中继端口，这样可以在同一端口上添加多个 VLAN。此外，还要从它们那里获取 VLAN ID，以便在操作系统层面进行配置。Linux 系统应该有两个接口。如果是物理服务器，我们建议在板载接口和 PCI 接口之间配置绑定，以避免主机端的网卡出现单点故障。绑定内核模块使用 lsmod 命令检查 Linux 系统是否已加载绑定模块。lsmod | grep -i bonding bonding 12451 0 默认情况下已加载。否则，请使用 modprobe 命令加载它。modprobe bonding 1) LACP 绑定配置我们将配置基于 LACP（Mode 4 – 802.3ad）的链路聚合绑定，通过组合名为 em1 和 p7p1 的两个接口，为绑定接口提供更大的带宽。1a) 创建 Bond 接口在目录 /etc/sysconfig/network-scripts/ 下创建绑定接口文件 ifcfg-bond0。vi /etc/sysconfig/network-scripts/ifcfg-bond0 TYPE=Bond DEVICE=bond0 NAME=bond0 BONDING_MASTER=yes BOOTPROTO=none ONBOOT=yes BONDING_OPTS="mode=4 miimon=100 lacp_rate=1" NM_CONTROLLED=no 1b) 配置第一个从接口配置你想要进行绑定的第一个从属接口 em1。请根据你的环境使用正确的接口名称。vi /etc/sysconfig/network-scripts/ifcfg-em1 TYPE=Ethernet BOOTPROTO=none DEVICE=em1 ONBOOT=yes MASTER=bond0 SLAVE=yes 1c) 配置第二个从接口配置你想要进行绑定的第二个从属接口 p7p1。 请根据你的环境使用正确的接口名称。vi /etc/sysconfig/network-scripts/ifcfg-p7p1 TYPE=Ethernet BOOTPROTO=none DEVICE=p7p1 ONBOOT=yes MASTER=bond0 SLAVE=yes 重启网络服务重启网络服务以启用绑定接口或使用 ifup 命令启动它们。systemctl restart network 2) 通过绑定接口进行 VLAN 标记LACP 绑定配置已完成，所有接口现已启动并运行。让我们按照以下步骤配置绑定接口上的 VLAN 标记。正如先决条件中所讨论的，以下是映射到相应以太网卡端口（em1 和 p7p1）和网络交换机端口的 VLAN。VLAN ID (221), VLAN N/W = 192.168.10.0/24VLAN ID (331), VLAN N/W = 192.168.20.0/242a) 将 VLAN 221 配置到 Bond0为 VLAN id 221 创建标记接口文件 /etc/sysconfig/network-scripts/ifcfg-bond0.221 并添加以下内容。vi /etc/sysconfig/network-scripts/ifcfg-bond0.221 DEVICE=bond0.221 BOOTPROTO=none ONBOOT=yes IPADDR=192.168.10.100 NETMASK=255.255.255.0 GATEWAY=192.168.10.1 VLAN=yes NM_CONTROLLED=no 2b) 将 VLAN 331 配置到 Bond0为 VLAN id 331 创建标记接口文件 /etc/sysconfig/network-scripts/ifcfg-bond0.331 并添加以下内容。vi /etc/sysconfig/network-scripts/ifcfg-bond0.331 DEVICE=bond0.331 BOOTPROTO=none ONBOOT=yes IPADDR=192.168.20.100 NETMASK=255.255.255.0 GATEWAY=192.168.20.1 VLAN=yes NM_CONTROLLED=no 重启网络服务重启网络服务以启用绑定接口或使用 ifup 命令启动它们。systemctl restart network 验证 VLAN 标记配置最后使用 ip 命令 验证 VLAN 标记接口是否已配置并启动和运行。是的，我可以看到 bondo.221@bond0 和 bon0.331@bond0 有两个不同的 IP，并且能够通过 ssh 访问系统，没有任何问题。因此，VLAN 标记按预期工作。结论恭喜，你已经了解了如何在 RHEL 系统上通过 LACP 绑定配置 VLAN 标记，该系统监听两个 VLAN。VLAN 标记不限于两个 VLAN，支持多个 VLAN，你可以根据该 VLAN 的网络配置添加 VLAN 标记。（题图：DA/2854516d-4d19-4008-a421-05f9a2a78368）via: https://www.2daygeek.com/configure-vlan-tagging-over-network-bonding-rhel/作者：Jayabal Thiyagarajan 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
了解在 Ubuntu 上安装 Docker 的两种官方方法。一种很简单，但可能会给你一个稍旧的版本。另一种方法稍显复杂，但能提供最新的稳定版本。使用 Docker 意味着开启一个新的计算领域，但如果你刚刚开始使用 Docker，安装可能看起来是一项艰巨的任务。在 Ubuntu 上安装 Docker 有两种推荐的方法：从 Ubuntu 的仓库安装 Docker：简单的单行命令，但提供旧版本使用 Docker 的官方仓库：工作量稍多，但提供了最新的稳定版本我将在本教程中讨论它们。方法 1：使用 Ubuntu 的仓库安装 Docker如果你不在意旧版本，并且不想设置和管理仓库，那么这是最适合你的方法。从更新仓库索引开始：sudo apt update 现在，你可以使用以下命令在 Ubuntu 中安装 Docker 以及 Docker Compose：sudo apt install docker.io docker-compose ? Docker 包被命名为 docker.io，因为在 Docker 出现之前就已经存在一个名为 docker（用于 Dockerlet 应用）的过渡包。因此，Docker 包必须被命名为其他名称。安装完成后，你可以使用以下命令检查安装的版本：docker -v 如你所见，它给了我 Docker 24.0.5。方法 2：在 Ubuntu 中安装最新稳定版本的 Docker如果你想要 Docker 的最新稳定版本，那么你可以从其官方仓库安装 Docker。步骤 1：删除任何现有的 Docker 包但在跳到安装部分之前，有必要删除所有以前安装的 Docker。要 卸载以前的 Docker，请使用以下命令。sudo apt remove docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc 步骤 2：安装依赖项第一步是安装一些必要的软件包，这些软件包将用于在本教程后面安装 Docker：sudo apt install ca-certificates curl gnupg lsb-release 你可能已经安装了部分或全部这些软件包，但确认安装没有什么坏处。上面的命令不会伤害你。步骤 3：添加 Docker 仓库的 GPG 密钥并将其添加到 sources.list现在，通过 apt 包管理器创建一个具有特殊权限的目录，用于存储加密密钥以进行包验证：sudo install -m 0755 -d /etc/apt/keyrings 接下来，如下所示 使用 curl 命令 下载并导入 Docker 的 GPG 密钥环：curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 下载 GPG 密钥后，使用 chmod 命令更改文件权限，以便系统上的每个用户都可以读取 GPG 密钥：sudo chmod a+r /etc/apt/keyrings/docker.gpg 最后，将 Docker 仓库添加到 sources.list.d 文件中：echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 就是这样！步骤 4：安装 Docker 和 Docker Compose现在，要使你对系统所做的更改生效，请更新系统仓库：sudo apt update 使用以下命令获取最新版本的 Docker 以及其他 Docker 组件和依赖项：sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ? 虽然 docker.io 包安装了大部分必需的 Docker 组件，但你需要在此处单独进行安装。要检查已安装的版本，请使用以下命令：docker -v 测试安装的另一个方法是在 Docker 中使用 “Hello World” 镜像。让我告诉你如何做。使用 hello-world 镜像来验证 Docker 安装运行 “Hello World” 程序是我们启动任何编程之旅时都遵循的标准做法，Docker 也是如此。Docker 为你提供了一个 “Hello World” 镜像，你可以使用它来测试安装。要安装并运行 “Hello World” 镜像，只需使用以下命令：sudo docker run hello-world 某些用户在执行上述命令时可能会收到错误消息“无法连接到 Docker 守护进程”：在这种情况下，重新启动系统并再次尝试安装 Docker Hello World 镜像，它将正常工作。? 额外提示：在 Ubuntu 中使用 Docker 而无需 sudo如果你注意到了，我使用 sudo 来拉取 Docker 镜像，这并不是使用 Docker 最方便的方式。如果你尝试在不使用 sudo 的情况下使用 Docker，则会出现错误：好吧，在本节中，我将向你展示如何在没有 sudo 的情况下使用 Docker。? 要执行所示步骤，必须具有超级用户权限！第一步是使用以下命令 创建一个名为 docker 的新组：sudo groupadd docker 完成后，使用以下命令将用户添加到 docker 组：sudo usermod -aG docker <用户名> ? 确保你只添加具有超级用户权限的用户。现在，注销并重新登录以使更改生效。但如果你使用的是虚拟机，那么必须重新启动。就是这样！从现在开始，你可以使用 docker 命令而不需要 sudo，就像我运行 Docker Hello World 镜像一样：就这样吧。这是安装 Docker 后要做的事情如果你刚刚开始，请参阅每个用户都必须了解的 基本 Docker 命令列表：21 个基本 Docker 命令我希望你觉得会有帮助。（题图：DA/759e483b-0be8-409e-bc58-ed19d99cbdd4）via: https://itsfoss.com/install-docker-ubuntu/作者：Sagar Sharma 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
网络应用防火墙（WAF）是一种在应用层监控网络流量的应用程序。OSI（开放系统互联） 是最常被网络相关讨论引用的网络流量框架之一。当数据包通过第 6 层（表示层）移动到第 7 层（应用层）时，它会进行解密或解码操作。这些操作可能会因异常解码和解释而产生漏洞，而这些漏洞可能被利用来打破标准应用上下文。注入就是这种漏洞的一种类型，而且因为传统的 IDS/IPS 设备无法应对这些威胁，所以其长时间以来一直是人们特别关注的问题。ModSecurity 简介ModSecurity 本质上就是 网络应用防火墙 web application firewall （WAF）引擎。它与 Apache、IIS 和 Nginx 兼容，并由第三方公司维护。该防火墙会将一份规则列表与由 Web 服务器/代理提供的 HTTP 头流进行交叉引用。目前这个仓库已经被简化，只包含主要的 LibModSecurity 库。你可以直接在自己的服务器实现中调用这个库，或通过特定编程语言的封装进行调用。其母公司的支持计划于 2024 年 7 月 1 日结束，之后这个项目将由开源社区维护。安装 Nginx 连接器Nginx 连接器 是一个 Nginx 动态模块，可以通过 Fedora 包 nginx-mod-modsecurity 进行安装。它依赖于 libmodsecurity.so，所以在这个使用场景中，这个包本身就是防火墙。[user@fedora ~]$ sudo dnf install -y nginx nginx-mod-modsecurity [user@fedora ~]$ rpm -qR nginx-mod-modsecurity config(nginx-mod-modsecurity) = 1.0.3-3.fc38 libc.so.6(GLIBC_2.4)(64bit) libmodsecurity.so.3()(64bit) nginx(abi) = 1.24.0 nginx-filesystem ... 安装完成后，你会见到连接器在 /etc/nginx 中添加了一些重要的文件。[user@fedora ~]$ rpm -ql nginx-mod-modsecurity /etc/nginx/modsecurity.conf # waf 配置 /etc/nginx/nginx.conf.modsecurity # nginx 示例配置 /usr/lib64/nginx/modules/ngx_http_modsecurity_module.so /usr/share/nginx/modules/mod-modsecurity.conf /usr/share/doc/nginx-mod-modsecurity/README.md ... 通过提供一些额外的配置指令，连接器对 Nginx 进行了扩展。下面的部分将演示 nginx.conf.modsecurity 文件中一些示例指令。指令的完整列表可以在 README.md 文件或项目的 GitHub 页面找到。启动网络应用防火墙nginx.conf.modsecurity 是我们将要运行的 Nginx 配置。解开如下所示的 modsecurity 行注释：[user@fedora ~]$ sudo sed -i 's/#modsec/modsec/g' /etc/nginx/nginx.conf.modsecurity [user@fedora ~]$ grep -C2 modsecurity /etc/nginx/nginx.conf.modsecurity # 如有需要，启用 ModSecurity WAF modsecurity on; # 如有需要，加载 ModSecurity CRS modsecurity_rules_file /etc/nginx/modsecurity.conf; 在 shell 中启动服务器并查看日志，确保在 modsecurity.conf 加载了七个默认规则。[user@fedora ~]$ sudo nginx -c /etc/nginx/nginx.conf.modsecurity [user@fedora ~]$ head /var/log/nginx/error.log 2023/10/21 23:55:09 [notice] 46218#46218: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/7/0) 2023/10/21 23:55:09 [notice] 46218#46218: using the "epoll" event method 2023/10/21 23:55:09 [notice] 46218#46218: nginx/1.24.0 2023/10/21 23:55:09 [notice] 46218#46218: OS: Linux 6.5.7-200.fc38.x86_64 通过发送一些不符合 Content-Type 头格式的数据来测试默认规则。[user@fedora ~]$ curl -X POST http://localhost -H "Content-Type: application/json" --data "<xml></xml>" [user@fedora ~]$ tail /var/log/modsec_audit.log ... ---rH5bFain---H-- ModSecurity: Warning. Matched "Operator `Eq' with parameter `0' against variable `REQBODY_ERROR' (Value: `1' ) [file "/etc/nginx/modsecurity.conf"] [line "75"] [id "200002"] [rev ""] [msg "Failed to parse request body."] [data "JSON parsing error: lexical error: invalid char in json text.\n"] [severity "2"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "10.0.2.100"] [uri "/"] [unique_id "169795900388.487044"] [ref "v121,1"] 用 OWASP 核心规则集扩展你的网络应用防火墙默认的 Nginx 连接器带有七条规则。OWASP Core Rule Set v3.3.5 则更为详尽，涵盖了许多场景。复制并提取规则的存档。[user@fedora ~]$ curl -fSL https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.5.tar.gz --output /tmp/v3.3.5.tar.gz [user@fedora ~]$ sudo tar -C /etc/nginx -xvf /tmp/v3.3.5.tar.gz [user@fedora ~]$ tree -L 1 /etc/nginx/ /etc/nginx/ ├── conf.d ├── default.d ├── modsecurity.conf # waf 配置 ├── nginx.conf ├── nginx.conf.modsecurity # nginx 启用 waf ├── coreruleset-3.3.5 ├ ├── rules # 规则目录 ├ ... ├ ... 现在，你在 Nginx 配置文件夹中有了一个包含所有当前 OWASP 规则的 rules 目录。接下来，让 Nginx 知道这些规则。以下操作指南来源于 OWASP INSTALL 文件。创建一个 crs.conf 文件，并在全局网络应用防火墙配置文件（ modsecurity.conf ）中包含所有相关的配置文件。[user@fedora ~]$ sudo cp /etc/nginx/coreruleset-3.3.5/crs-setup.conf.example /etc/nginx/coreruleset-3.3.5/crs.conf [user@fedora ~]$ echo -e "\nInclude /etc/nginx/coreruleset-3.3.5/crs.conf" | sudo tee -a /etc/nginx/modsecurity.conf [user@fedora ~]$ echo -e "\nInclude /etc/nginx/coreruleset-3.3.5/rules/*.conf" | sudo tee -a /etc/nginx/modsecurity.conf [user@fedora ~]$ tail /etc/nginx/modsecurity.conf Include /etc/nginx/coreruleset-3.3.5/crs.conf Include /etc/nginx/coreruleset-3.3.5/rules/*.conf 根据文档，包含这些文件的顺序很重要。上面的 tee 的命令将新的 Include 行放在了 modsecurity.conf 文件的末尾。现在，用这个新配置重启 Nginx。[user@fedora ~]$ sudo nginx -s stop && sudo nginx -c /etc/nginx/nginx.conf.modsecurity [user@fedora ~]$ tail /var/log/nginx/error.log 2023/10/22 10:53:23 [notice] 202#202: exit 2023/10/22 10:53:50 [notice] 230#230: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/921/0) 2023/10/22 10:53:50 [notice] 230#230: using the "epoll" event method 2023/10/22 10:53:50 [notice] 230#230: nginx/1.24.0 2023/10/22 10:53:50 [notice] 230#230: OS: Linux 6.5.7-200.fc38.x86_64 2023/10/22 10:53:50 [notice] 230#230: getrlimit(RLIMIT_NOFILE): 524288:524288 2023/10/22 10:53:50 [notice] 231#231: start worker processes 注意，Nginx 成功加载了 921 条规则。还需要做一些测试来确保规则实际上是被网络应用防火墙检查过的。这里再次引用 INSTALL 文件中的 “Testing the Installation” 片段。[user@fedora ~]$ curl 'http://localhost/?param=''> ' [user@fedora ~]$ tail /var/log/modsec_audit.log ... ---8NSpdnLe---H-- ModSecurity: Warning. detected XSS using libinjection. [file "/etc/nginx/coreruleset-3.3.5/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf"] [line "38"] [id "941100"] [rev ""] [msg "XSS Attack Detected via libinjection"] [data "Matched Data: XSS data found within ARGS:param: > "] [severity "2"] [ver "OWASP_CRS/3.3.5"] ... 结论本文演示了如何为 Nginx 服务器配置网络应用防火墙。这个部署使用了标准规则和 OWASP Core Rule Set v3.3.5。演示的防火墙在检测模式中运行并记录不寻常的行为。将防火墙运行在防御模式要对 modsecurity.conf 进行更多改动。请参考 ModSecurity Reference Manual v3.x) 获取如何启用防御模式和更多信息。祝你好运。（题图：DA/7ec85bc4-b209-4fc6-9275-8f7d1430f6ca）via: https://fedoramagazine.org/a-web-application-firewall-for-nginx/作者：Roman Gherta 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
2011 年 3 月，苹果公司提出 RFC 6186，描述了如何利用域名系统服务（DNS SRV）记录来查找电子邮件的提交以及访问服务。现在 Postfix 从 3.8.0 版本开始支持 RFC 中提出的设计。这个新增功能让你可以使用 DNS SRV 记录进行负载分配和自动配置。DNS SRV 记录的形态DNS SRV 记录定义在 RFC 2782 中，它指定在区域文件中，并且包含了服务名称、传输协议规范、优先级、权重、端口，以及提供该服务的主机。_submission._tcp SRV 5 10 50 bruce.my-domain.com. 字段值意义服务名称submission服务名为 submission传输协议规范tcp本服务使用 TCP 协议优先级5服务器优先级设为 5（数值越小，优先级越高）权重10服务器应承担的负载部分端口50服务器监听连接的端口目标bruce.my-domain.com.提供此服务的服务器名称记录解释服务器选择算法客户端应该按照 RFC 2782 中描述的方式解析 SRV 记录。这意味着，首先尝试联系拥有最高优先级（最小的优先级数字）的服务器。如果该服务器无回应，那么重试联系拥有同样或者更低优先级的下一台服务器。当有多台服务器拥有同样优先级的时候，应随机选择其中一台，但是必须确保选择记录的概率符合下列公式：其中 i 是 SRV 记录的标识，k 是具有相同优先级的 SRV 记录的数量。在现实中，这意味着如果你有两台服务器，其中一台的处理能力是另一台的三倍，那么你应该给第一台服务器的权重赋于另一台三倍的值。这样就能保证更强大的服务器会接收到大约 75% 的客户端请求，而另一台接收大约 25% 的请求。这些原则使得 SRV 记录能够同时作为客户端自动配置及在服务器之间分配工作负载的工具。看看以下这个记录的例子：_submission._tcp SRV 0 0 2525 server-one _submission._tcp SRV 1 75 2625 server-two _submission._tcp SRV 1 25 2625 server-three 这里 server-one 总是会被首选来进行联系。如果 server-one 无回应，客户端就会将剩下优先级为 1 的两个记录顺序打乱，生成一个从 0 到 100 的随机数，如果第一条记录的运行总和大于或者等于这个随机数，它就会尝试去联系这个记录。否则，客户端会倒序联系所有服务器。注意，客户端会向它优先成功连接的服务器发送请求。示例配置请考虑以下这种情况。你想为大量的电脑配置 Postfix，使其通过公司的邮件服务器利用 SRV 记录转发外部电邮。为了达到这个目标，你需要在每台电脑的 Postfix 中配置 relayhost 参数，即邮件用户代理（MUA）。如果将 relayhost 参数的值设置为 $mydomain，你的机器将开始为你的域名查找 MX 记录，并尝试按照它们的优先级顺序发送邮件。这种方法虽然有效，但是可能会遇到负载平衡问题。Postfix 会使用优先级最高的服务器，直到其变为无响应才会联系其他备用服务器。此外，如果你在环境中使用了动态分配的端口，你无法指明哪个端口正在被特定的服务器使用。使用 SRV 记录，你可以应对这些挑战，并在需要改变服务器端口的时候维持服务器的平滑运行。区域文件为了使得 DNS 服务器提供信息给客户端，可以参考以下使用服务器 server-one、server-two、server-three 作为中继，并把服务器 server-four 配置为接收测试邮件的区域文件示例。$TTL 3600 @ IN SOA example-domain.com. root.example-domain.com. ( 1571655122 ; 区域文件的序列号 1200 ; 刷新时间 180 ; 发生问题时的重试时间 1209600 ; 过期时间 10800 ) ; 查询失败时的最大缓存时间 ; IN NS ns1 IN A 192.168.2.0 ; ns1 IN A 192.168.2.2 server-one IN A 192.168.2.4 server-two IN A 192.168.2.5 server-three IN A 192.168.2.6 server-four IN A 192.168.2.7 _submission._tcp SRV 0 0 2525 server-one _submission._tcp SRV 1 50 2625 server-two _submission._tcp SRV 1 50 2625 server-three @ MX 0 server-four Postfix MUA 配置设置客户端机器去查找 SRV 记录：use_srv_lookup = submission relayhost = example-domain.com:submission 通过这个配置，你的客户端机器上的 Postfix 实例会联络到 example-domain 的 DNS 服务器，然后获取邮件提交的 SRV 记录。在这个例子中，server-one 有最高的优先级，Postfix 会先试图连接它。然后，Postfix 随机的选择剩下的两个服务器其中一个去尝试连接。这个配置确保了大约有 50% 的机会会优先联系到服务器一。注意，SRV 记录的权重值并不等同于百分比。你也可以用 1 和 1 这样的值达到同样的目标。同时，Postfix 也知道 server-one 在监听 2525 端口，而 server-two 在监听 2625 端口。如果你正在缓存检索到的 DNS 记录，并且你动态改变 SRV 记录，那么设置一个低的生存时间（TTL）对你的记录是很重要的。整套设置你可以通过下面的方式尝试这个配置，包含 podman 和在此处提供的 compose 文件：$ git clone https://github.com/TomasKorbar/srv_article $ cd srv_article/environment $ podman-compose up $ podman exec -it article_client /bin/bash root@client # ./senddummy.sh root@client # exit 完成配置之后，你可以检查日志，查看邮件是否经过 server-one 并最终投递到 server-four。$ podman stop article_server1 $ podman exec -it article_client /bin/bash root@client # ./senddummy.sh root@client # ./senddummy.sh root@client # ./senddummy.sh root@client # ./senddummy.sh root@client # ./senddummy.sh root@client # ./senddummy.sh root@client # exit 现在 server-one 已经关闭了，这六封邮件将会由 server-two 或者 server-three 中转发出去。仔细看一下 Dockerfiles 以更深地理解这个配置。通过执行：$ podman-compose down 完成示例的操作。（题图：DA/241079fe-58d6-4dc6-8801-f0fd19dfd64b）via: https://fedoramagazine.org/using-postfix-dns-srv-record-resolution-feature/作者：Tomáš Korbař 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
用这些技巧释放 sudo 的力量 ?你应该熟悉 sudo 吧？肯定有过使用的经验。对多数 Linux 用户来说，sudo 就像一个神器，赋予了他们作为 root 用户执行任意命令或切换到 root 用户身份的能力。其实这只掌握了一半的真相。sudo 绝非仅仅只是一条命令，sudo 是一款你可以根据需求和偏好去定制的工具。Ubuntu、Debian 以及其他的发行版在默认的配置下，赋予了 sudo 以 root 用户的身份执行任意命令的权限。这让很多用户误以为 sudo 就像一个魔法开关，瞬间可以获取到 root 权限。比如说，系统管理员可以设置成只有属于特定的 dev 组的部分用户才能用 sudo 来执行 nginx 命令。这些用户将无法用 sudo 执行任何其他命令或切换到 root 用户。如果你对此感到惊讶，那很可能是你一直在使用 sudo，但对其底层的工作原理并没有太多了解。在这个教程中，我并不会解释 sudo 是如何运作的，这个主题我会在另一天讲解。在这篇文章中，你将看到 sudo 的不同特性可以如何被调试和改进。有些可能真的很有用，有些可能完全没什么帮助，但是挺有趣。? 请不要随意去尝试所有提到的改进。如果处理不慎，你可能会遭遇无法运行 sudo 的混乱状态。在大多数情况下，平静阅读并知道这些就好。如果你决定尝试一些改进步骤，请先备份你的系统设置，这样在需要的时候能把事情恢复到正常。1、编辑 sudo 配置时，请始终使用 visudosudo 命令是通过 /etc/sudoers 文件进行配置的。虽然你可以用你最喜欢的 终端文本编辑器 编辑这个文件，比如 Micro、NeoVim 等，但你千万不要这么做。为什么这么说呢？因为该文件中的任何语法错误都会让你的系统出问题，导致 sudo 无法工作。这可能会使得你的 Linux 系统无法正常使用。你只需要这样使用即可：sudo visudo 传统上，visudo 命令会在 Vi 编辑器中打开 /etc/sudoers 文件。如果你用的是 Ubuntu，那么会在 Nano 中打开。这么做的好处在于，visudo 会在你试图保存更改时执行语法检查。这能确保你不会因为语法错误而误改 sudo 配置。好了！现在你可以看看 sudo 配置的一些改变。? 我建议你备份 /etc/sudoers 文件（sudo cp /etc/sudoers /etc/sudoers.bak）。这样，如果你不确定你做了哪些更改，或者你想恢复到默认的 sudo 配置，那你可以从备份文件中复制。2、输入 sudo 密码时显示星号我们的这种输入行为是从 UNIX 系统中继承下来的。当你在终端输入 sudo 密码时，屏幕上不会有任何显示。这种缺乏反馈的现象，往往让新的 Linux 用户怀疑自己的系统已经卡住了。人们常说，这是一项安全功能。或许在上个世纪是这样，但我个人觉得我们没有必要继续这样下去。不过，一些发行版，如 Linux Mint，已经对 sudo 进行了优化，当你输入密码时会显示星号。这样的方式更符合我们的日常经验。如果想让 sudo 输入密码时显示星号，运行 sudo visudo 并找到以下行：Defaults env_reset 然后将其更改为：Defaults env_reset,pwfeedback ? 在某些发行版中，比如 Arch，你可能找不到 Defaults env_reset 这一行。如果这样的话，只需新增一行 Defaults env_reset, pwfeedback 就可以了。现在，当 sudo 需要你输入密码时，你会看到输入的密码变成了星号。✋ 如果你注意到即使密码正确也无法通过一些图形化应用，如软件中心，那就该撤销这项更改。一些较旧的论坛帖子曾提到过此类问题，虽然我自己还未遇到过。3、增加 sudo 密码超时时限当你首次使用 sudo 时，它会要求输入密码。但在随后相当一段时间里，你使用 sudo 执行命令就无需再次输入密码。我们将这个时间间隔称为 sudo 密码超时 （暂且称为 SPT，这是我刚刚编的说法，请不要真的这样称呼 ?）。不同的发行版有不同的超时时间。可能是 5 分钟，也可能是 15 分钟。你可以根据自己的喜好来改变这个设置，设定一个新的 sudo 密码超时时限。像你之前看到的，编辑 sudoers 文件，找到含有 Defaults env_reset 的行，并在此行添加 timestamp_timeout=XX，使其变成如下形式：Defaults env_reset, timestamp_timeout=XX 其中 XX 是以分钟为单位的超时时长。如果你还有其他参数，例如你在上一节中看到的星号反馈，它们都可以在一行中组合起来：Defaults env_reset, timestamp_timeout=XX, pwfeedback ? 同样地，你还可以控制密码重试的次数上限。使用 passwd_tries=N 来修改用户可以输入错误密码的次数。4、在不输入密码的情况下使用 sudo行！你已经增加了 sudo 密码超时时限（或者称之为 SPT。哇塞！你还在坚持这个叫法 ?）。这样很好。我的意思是，毕竟没人愿意每几分钟就输入一次密码。扩大超时时限是一方面，另一方面则是尽可能不去使用它。是的，你没听错。你就是可以在无需输入密码的情况下使用 sudo。从安全角度来看，这听起来似乎很冒险，对吧？的确如此，但在某些实际情况下，你确实会更青睐无密码的 sudo。例如，如果你需要远程管理多台 Linux 服务器，并为了避免总是使用 root，你在这些服务器上创建了一些 sudo 用户。辛酸的是，你会有太多的密码。而你又不想对所有的服务器使用同一的 sudo 密码。在这种情况下，你可以仅设置基于密钥的 SSH 访问方式，并允许使用无需密码的 sudo。这样，只有获得授权的用户才能访问远程服务器，也不用再记住 sudo 密码。我在 DigitalOcean 上部署的测试服务器上就采用了这种方法，用来测试开源工具和服务。好处是这可以按用户进行设置。使用以下命令打开 /etc/sudoers 文件进行编辑：sudo visudo 然后添加如下行：user_name ALL=(ALL) NOPASSWD:ALL 当然，你需要将上面行中的 user_name 替换为实际的用户名。保存文件后，你就可以享受无密码的 sudo 生活了。5、配置独立的 sudo 日志文件查阅 syslog 或 journal 日志，我们可以找到关于 sudo 的所有条目，但若需要单独针对 sudo 的记录，可以专门创建一个自定义的日志文件。例如，选择 /var/sudo.log 文件来存储日志。这个新的日志文件无需手动创建，如果不存在，系统会自动生成。编辑 /etc/sudoers 文件，采用 visudo 命令，并在其中添加以下内容：Defaults logfile="/var/log/sudo.log" 保存该文件后，便可以在其中查看哪些命令在何时、由哪位用户通过 sudo 运行了。6、限制特定用户组使用 sudo 执行特定命令这是一种高级解决方案，系统管理员在需要跨部门共享服务器的多用户环境中会使用。开发者可能会需要以 root 权限运行 Web 服务器或其他程序，但全权给予他们 sudo 权限会带来安全风险。我建议在群组级别进行此项操作。例如，创建命名为 coders 的群组，并允许它们运行在 /var/www 和 /opt/bin/coders 目录下的命令（或可执行文件），以及 inxi 命令（路径是 /usr/bin/inxi 的二进制文件）。这是一个假想情景，实际操作请谨慎对待。接下来，用 sudo visudo 编辑 sudoer 文件，再添加以下行:%coders ALL=(ALL:ALL) /var/www,/opt/bin/coders,/usr/bin/inxi 如有需要，可以添加 NOPASSWD 参数，这样允许使用 sudo 运行的命令就不再需要密码了。关于 ALL=(ALL:ALL) 的详细解读，我们将会在其他文章中进行讲解，毕竟这篇文章已经解释的内容足够多了。7、检查用户的 sudo 权限好吧，这是个小提示，而不是系统调优技巧。如何确认一个用户是否具有 sudo 权限呢？可能有人会说，查看他们是否是 sudo 组的成员。但这并不一定准确，因为有些发行版用的是 wheel 代替 sudo 分组。更佳的方法是利用 sudo 内建的功能，看看用户具有哪种 sudo 权限：sudo -l -U user_name 这将显示出用户具有执行部分命令或所有命令的 sudo 权限。如你所见，我拥有自定义日志文件、密码反馈以及执行所有命令的 sudo 权限。如果一个用户完全没有 sudo 权限，你将看到如下提示：User prakash is not allowed to run sudo on this-that-server. ? 附加内容：输错 sudo 密码时，让系统“侮辱”你这是个我在文章开头提到的“无用”小调整。我想你在使用 sudo 时肯定曾误输过密码，对吧？这个小技巧就是，在你每次输错密码时，让 sudo 抛出随机的“侮辱”。用 sudo visudo 修改 sudo 配置文件，然后添加以下行：Defaults insults 修改后，你可以故意输错密码，测试新的设置。你可能在想，谁会喜欢被侮辱呢？只有粉丝可以以直白的方式告诉你 ?你是如何运用 sudo 的？我知道定制化的可能性无穷无尽，但其实，一般的 Linux 用户并不会去自定义 sudo。尽管如此，我还是热衷于与你分享这些因为你可能会发现一些新奇且实用的东西。? 那么，你有发现什么新的东西吗？请在评论区告诉我。你有一些秘密的 sudo 技巧欢迎和大家分享！（题图：DA/a12900e5-e197-455e-adfc-0b52e4305b91）via: https://itsfoss.com/sudo-tips/作者：Abhishek Prakash 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
扩展 VxFX 文件系统是 Linux/Unix 管理员的一项日常任务，可以通过以下文章中描述的几个步骤在线完成此任务：在此，磁盘组没有足够的可用空间，因此我们将在现有磁盘组（DG）中添加新磁盘，然后调整其大小。相关文章：如何在 Linux 中创建 VxVM 卷和文件系统如何在 Linux 上创建共享 VxFS 文件系统步骤 1：识别文件系统使用 df 命令 检查要增加/扩展的文件系统，并记下以下输出中的磁盘组（DG）和卷名称，稍后在运行 vxdg 和 vxresize 命令时将使用这些名称。# df -hP /data Filesystem Size Used Avail Use% Mounted on /dev/vx/dsk/testdg/testvol 9.0G 8.4G 0.6G 95% /data 根据上面的输出，VxFS 文件系统大小为 9.0 GB，我们希望额外扩展 5 GB 并发布此活动，VxFS 大小将为 14 GB。在本例中，DG 名称为 testdg，卷名称为 testvol。步骤 2：获取新磁盘/LUN新磁盘必须由存储团队映射到主机，这可能需要 CR 批准，因此提出 CR 并向相关团队添加必要的任务，并且还包括此活动的回滚计划。步骤 3：扫描磁盘/LUN存储团队将新 LUN 映射到主机后，获取 LUN id 并将其保存。使用以下命令扫描 LUN 以在操作系统级别发现它们。for disk_scan in `ls /sys/class/scsi_host`; do echo "Scanning $disk_scan…Completed" echo "- - -" > /sys/class/scsi_host/$disk_scan/scan done Scanning host0...Completed Scanning host1...Completed . . Scanning host[N]...Completed 扫描完成后，使用以下命令查看是否在操作系统级别找到给定的 LUN。lsscsi --scsi | grep -i [Last_Five_Digit_of_LUN] 步骤 4：在 VxVM 中查找磁盘默认情况下，所有可用磁盘对 Veritas 卷管理器（VxVM）都是可见的，可以使用 vxdisk 命令列出这些磁盘，如下所示。# vxdisk -e list DEVICE TYPE DISK GROUP STATUS OS_NATIVE_NAME ATTR emc_01 auto:cdsdisk disk1 testdg online sdd - emc_02 auto:cdsdisk disk2 testdg online sde - emc_03 auto:none - - online invalid sdf - sda auto:LVM - - LVM sda - sdb auto:LVM - - LVM sdb - 磁盘 sdf 的状态显示为 Online invalid 表示该磁盘不受 VxVM 控制。但是，请使用 smartctl 命令仔细检查 LUN id，以确保你选择了正确的磁盘。smartctl -a /dev/sd[x]|grep -i unit 如果磁盘未填充到 VxVM，请执行以下命令扫描操作系统设备树中的磁盘设备。vxdisk scandisks 步骤 5：在 VxVM 中初始化磁盘当磁盘在步骤 4 中对 VxVM 可见，那么使用 vxdisksetup 命令初始化磁盘，如下所示：vxdisksetup -i sdf 上面的命令将磁盘 sdf 带到 Veritas 卷管理器（VxVM），并且磁盘状态现在更改为 online。步骤 6：将磁盘添加到 VxVM 中的磁盘组（DG）vxdg 命令对磁盘组执行各种管理操作。在此示例中，我们将使用它向现有磁盘组（DG）添加新磁盘。vxdg -g [DG_Name] adddisk [Any_Name_to_Disk_as_per_Your_Wish=Device_Name] vxdg -g testdg adddisk disk3=emc_03 运行上述命令后，磁盘名称为 disk3 且磁盘组名称为 testdg 已针对 emc_03 设备进行更新 如下所示：# vxdisk -e list DEVICE TYPE DISK GROUP STATUS OS_NATIVE_NAME ATTR emc_01 auto:cdsdisk disk1 testdg online sdd - emc_02 auto:cdsdisk disk2 testdg online sde - emc_03 auto:none disk3 testdg online sdf - sda auto:LVM - - LVM sda - sdb auto:LVM - - LVM sdb - 步骤 7：检查磁盘组（DG）中的可用空间要确定连接卷有多少可用空间，请运行：vxassist -g testdg maxsize 步骤 8：扩展 VxVM 卷和 VxFS 文件系统我们为此活动添加了 5GB LUN，因此额外扩展了 VxVM 卷和 VxFS 文件系统 5GB，如下所示：vxresize -b -g [DG_Name] [Volume_Name] +[Size_to_be_Increased] vxresize -b -g testdg testvol +5g 这里：vxresize：命令-b：在后台执行调整大小操作（可选）。-g：将命令的操作限制为给定磁盘组，由磁盘组 ID 或磁盘组名称指定。testdg：我们的磁盘组（DG）名称testvol`：我们的卷名称+5g：此卷将额外增加 5GB。步骤 9：检查扩展 VxFS 文件系统最后，使用 df 命令检查 /data 的扩展 VxFS：# df -hP /data Filesystem Size Used Avail Use% Mounted on /dev/vx/dsk/testdg/testvol 14G 8.4G 5.6G 68% /data 总结在本教程中，我们向你展示了如何向现有磁盘组（DG）添加新磁盘，以及如何通过几个简单步骤在 Linux 中扩展 VxVM 卷和 VxFS 文件系统。如果你有任何问题或反馈，请随时在下面发表评论。（题图：MJ/3fe4fdb7-99da-4b8f-a818-0ae232e6fbcc）via: https://www.2daygeek.com/extend-increase-vxvm-volume-vxfs-filesystem-linux/作者：Jayabal Thiyagarajan 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
在某些情况下，你需要映射存储 LUN（逻辑单元号）、块设备、LVM（LV 和 VG 名称）和文件系统（FS）信息以进行文件系统扩展或灾难恢复（DR）操作。这是大多数 Linux 管理员的例行活动，我们通常使用一些脚本来显示针对 SAN LUN 的块设备映射，然后我们将手动添加 LVM 和文件系统信息来完成操作。今后，你无需手动干预此活动，因为这些信息可以通过 Shell 脚本进行映射，如下所示。参考以下类似文章：如何在 Linux 中查找 SAN 磁盘 LUN id如何在 Linux 中将 ASM 磁盘映射到物理磁盘如何在 Linux 中映射 SAN LUN、磁盘和文件系统在 Linux 中映射 LUN、磁盘、LVM 和文件系统的 Shell 脚本这个 Shell 脚本可帮助你识别哪些 SAN 磁盘映射到 Linux 上的哪些块设备、LV、VG 和文件系统。请注意： 我们排除了 sda 磁盘，因为这是操作系统（OS）盘，它有多个分区。vi block_device_mapping_with_LUN_FS_LVM.sh #!/bin/bash for bdevice in `lsblk | grep disk | awk '{print $1}' | grep -v 'sda'`; do for mpoint in `lsblk /dev/$bdevice | grep lvm | awk '{print $NF}'`; do LVM_INFO=`lvs -o +devices | grep -i $bdevice | awk '{print $1,$2}'` LUN_ID=`lsscsi --scsi | grep $bdevice | awk '{print $NF}'` echo "$bdevice --> $mpoint --> $LVM_INFO --> $LUN_ID" done done 设置 block_device_mapping_with_LUN_FS_LVM.sh 文件的可执行权限。chmod +x block_device_mapping_with_LUN_FS_LVM.sh 最后运行脚本查看结果。sh block_device_mapping_with_LUN_FS_LVM.sh 注意： 在上面的输出中，设备 sdb 不会显示任何 LUN 信息，因为它是从 VMWare 端添加的虚拟磁盘，没有任何 LUN。其他 3 块磁盘是从存储映射的，这就是为什么可以看到 LUN 信息。如果你想即时运行上述脚本，请使用下面的一行脚本。for bdevice in `lsblk | grep disk | awk '{print $1}' | grep -v 'sda'`; do for mpoint in `lsblk /dev/$bdevice | grep lvm | awk '{print $NF}'`; do LVM_INFO=`lvs -o +devices | grep -i $bdevice | awk '{print $1,$2}'`; LUN_ID=`lsscsi --scsi | grep $bdevice | awk '{print $NF}'`; echo "$bdevice --> $mpoint --> $LVM_INFO --> $LUN_ID"; done; done sdb --> [SWAP] --> swap2lv swapvg --> - sdc --> /appserver --> appserver_lv appserver_vg --> 360000670000415600477312020662021 sdd --> /data --> data_lv data_vg --> 360000670000415600477312020662022 sde --> /backup --> backup_lv backup_vg --> 360000670000415600477312020662023 总结在本教程中，我们向你展示了如何在 Linux 上检查 SAN 提供的 LUN 以及底层操作系统磁盘、LV 名称、VG 名称和关联的文件系统。如果你有任何问题或反馈，请随时在下面发表评论。（题图：MJ/f5da2270-4e5a-4b2c-8998-fae974214384）via: https://www.2daygeek.com/map-san-lun-physical-disk-filesystem-lvm-info-linux/作者：Rasool Cool 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
网络 绑定 Bonding （ 成组 Teaming ） 是 Linux 的一项内核特性，它让我们可以将多个网络接口（例如 ens192、ens224）聚合为一个专有的虚拟网络接口，被称为通道绑定（bond0）。这样做能够提升吞吐量并增加冗余备份。网络绑定一共支持 7 种模式，你可以根据实际需求进行设置。 链接聚合控制协议 Link Aggregation Control Protocol （LACP）， 即模式 4（802.3ad）因其支持链接聚合与冗余而被广泛应用。在本篇文章中，我们将引导你学习如何在 RHEL 系统中配置网卡（网络）绑定。LACP 绑定的前置条件网络团队需要在网络交换机的端口上开启 LACP（802.3ad）来实现链接的聚合。一个 Linux 系统应该配备至少两个网络接口。对于物理服务器，我们推荐在板载接口与 PCI 接口间进行绑定配置，以避免在主机端的网络卡出现单点故障。Bonding 模块你可以使用 lsmod 命令来确认你的 Linux 系统是否已经加载了 bonding 模块。lsmod | grep -i bonding bonding 12451 0 系统应该默认已加载。如果未看到，可以运用 modprobe 命令进行加载。modprobe bonding 创建绑定接口在 /etc/sysconfig/network-scripts/ 路径下，创建一个名为 ifcfg-bond0 的绑定接口文件。依据你的网络情况，你可能需要修改诸如 IP、MASK 以及 GATEWAY 等值。vi /etc/sysconfig/network-scripts/ifcfg-bond0 TYPE=Bond DEVICE=bond0 NAME=bond0 BONDING_MASTER=yes BOOTPROTO=none ONBOOT=yes IPADDR=192.168.1.100 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 BONDING_OPTS="mode=4 miimon=100 lacp_rate=1" 参数描述BONDING_MASTER=yes表示设备是一个绑定主设备。mode=4绑定模式是 IEEE 802.3ad 动态链接聚合（LACP）。miimon=100定义以毫秒单位的 MII 链路监测频率，这决定了多久检查每个从属链路的状态一次以寻找失败的链路。0 值将禁用 MII 链路监测。100 是个不错的初始值。lacp_rate=1一个设置项，规定我们将以何种频率要求我们的链路伙伴每秒钟发送 LACPDU。默认为慢，即 0。配置第一个子接口修改你希望添加到绑定中的第一个子接口。请根据你的实际环境使用合适的接口名。vi /etc/sysconfig/network-scripts/ifcfg-ens192 TYPE=Ethernet BOOTPROTO=none DEVICE=ens192 ONBOOT=yes MASTER=bond0 SLAVE=yes 配置第二个子接口修改你希望添加到绑定中的第二个子接口。请根据你的实际环境使用合适的接口名。vi /etc/sysconfig/network-scripts/ifcfg-ens224 TYPE=Ethernet BOOTPROTO=none DEVICE=ens224 ONBOOT=yes MASTER=bond0 SLAVE=yes 重启网络服务重启网络服务以激活绑定接口。systemctl restart network 验证绑定配置你可以借助 ip 命令 来查看绑定接口以及其子接口的情况。可以看到，bond0 现在已启动并在运行。查阅绑定接口状态检查以下文件，你可以看到绑定接口及其子接口的详细信息。输出结果应该看起来很不错，我们能看到诸如绑定模式，MII 状态，MII 轮询间隔，LACP 速率，端口数量等信息。cat /proc/net/bonding/bond0 Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011) Bonding Mode: IEEE 802.3ad Dynamic link aggregation Transmit Hash Policy: layer (0) MII Status: up MII Polling Interval (ms): 100 Up Delay (ms): 0 Down Delay (ms): 0 802.3ad info LACP rate: fast Min links: 0 Aggregator selection policy (ad_select): stable System priority: 65535 System MAC address: c8:5b:76:4d:d4:5c Active Aggregator Info: Aggregator ID: 1 Number of ports: 2 Actor Key: 15 Partner Key: 32773 Partner Mac Address: e4:a7:a0:32:fc:e9 Slave Interface: ens192 MII Status: up Speed: 10000 Mbps Duplex: full Link Failure Count: 0 Permanent HW addr: c8:5b:76:4d:d4:5c Slave queue ID: 0 Aggregator ID: 1 Actor Churn State: none Partner Churn State: none Actor Churned State: 0 Partner Churned State: 0 details actor lacp pdu: system priority: 65535 system mac address: c8:5b:76:4d:d4:5c port key: 15 port priority: 255 port number: 1 port state: 63 details Partner lacp pdu: system priority: 32667 system mac address: e4:a7:a0:32:fc:e9 oper key: 32773 port priority: 32768 port number: 290 port state: 61 Slave Interface: ens224 MII Status: up Speed: 10000 Mbps Duplex: full Link Failure Count: 0 Permanent HW addr: e4:a7:a0:32:fc:e9 Slave queue ID: 0 Aggregator ID: 1 Actor Churn State: none Partner Churn State: none Actor Churned State: 0 Partner Churned State: 0 details actor lacp pdu: system priority: 65535 system mac address: e4:a7:a0:32:fc:e9 port key: 15 port priority: 255 port number: 2 port state: 63 details Partner lacp pdu: system priority: 32667 system mac address: c8:5b:76:4d:d4:5c oper key: 32773 port priority: 32768 port number: 16674 port state: 61 容错/冗余测试为了验证容错性和连接速度，你可以逐个断开接口，然后检查服务器是否仍旧可达。测试用例-1：当两个子接口都启动并运行时，使用 ethtool 命令 检查链路速度。测试用例-2：断开第一个子接口，然后尝试访问系统。测试用例-3：断开第二个子接口，然后尝试访问系统。测试用例-1：如果你想检测下连接速度：没错，我在 bond0 上看到了 20 Gbps 的速度，因为每个子接口支持 10 Gbps。ethtool bond0 Settings for bond0: Supported ports: [ ] Supported link modes: Not reported Supported pause frame use: No Supports auto-negotiation: No Supported FEC modes: Not reported Advertised link modes: Not reported Advertised pause frame use: No Advertised auto-negotiation: No Advertised FEC modes: Not reported Speed: 20000Mb/s Duplex: Full Port: Other PHYAD: 0 Transceiver: internal Auto-negotiation: off Link detected: yes 测试用例-2：现在我们将关闭第一个子接口。ifdown ens192 Device 'ens192' successfully disconnected. 通过 ssh 尝试访问系统。没问题，系统现在是可以访问的。ssh [email protected] 由于已经有一个子接口关闭，你现在在 bond0 上只能看到 10 Gbps 的速度。ethtool bond0 | grep -i speed Speed: 10000Mb/s 现在，我们再次查看绑定接口的状态。可以看出，只有一个子接口处于活跃状态。cat /proc/net/bonding/bond0 测试用例-3：我们来关闭第二个子接口，并进行类似测试用例-2 的测试：ifdown ens224 Device 'ens224' successfully disconnected. 结语我希望你已经掌握了在 RHEL 上配置 LACP 绑定的方法。在本教程中，我们为你展示了在 RHEL 系统配置网络绑定或网卡聚合的最简单方式。如果你有任何疑问或者反馈，欢迎在下面留言。（题图：MJ/939f6ba6-eb46-480d-8879-3a422c7425d2）via: https://www.2daygeek.com/configure-network-bonding-nic-teaming-rhel/作者：Jayabal Thiyagarajan 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
在这篇文章中，我们将向你展示如何在 Kubernetes（k8s）集群中设置动态 NFS 配置。Kubernetes 中的动态 NFS 存储配置允许你按需自动为 Kubernetes 应用配置和管理 NFS（网络文件系统）卷。它允许创建持久卷（PV）和持久卷声明（PVC），而无需手动干预或预配置存储。NFS 配置程序负责动态创建 PV 并将其绑定到 PVC。它与 NFS 服务器交互，为每个 PVC 创建目录或卷。先决条件预装 Kubernetes 集群具有 Kubernetes 集群管理员权限的普通用户互联网连接事不宜迟，让我们深入探讨步骤：步骤 1、准备 NFS 服务器就我而言，我将在 Kubernetes 主节点（Ubuntu 22.04）上安装 NFS 服务器。登录主节点并运行以下命令：$ sudo apt update $ sudo apt install nfs-kernel-server -y 创建以下文件夹并使用 NFS 共享它：$ sudo mkdir /opt/dynamic-storage $ sudo chown -R nobody:nogroup /opt/dynamic-storage $ sudo chmod 777 /opt/dynamic-storage 在 /etc/exports 文件中添加以下条目：$ sudo vi /etc/exports /opt/dynamic-storage 192.168.1.0/24(rw,sync,no_subtree_check) 保存并关闭文件。注意：不要忘记更改导出文件中适合你的部署的网络。要使上述更改生效，请运行：$ sudo exportfs -a $ sudo systemctl restart nfs-kernel-server $ sudo systemctl status nfs-kernel-server 在工作节点上，使用以下 apt 命令安装 nfs-common 包。$ sudo apt install nfs-common -y 步骤 2、安装和配置 NFS 客户端配置程序NFS 子目录外部配置程序在 Kubernetes 集群中部署 NFS 客户端配置程序。配置程序负责动态创建和管理由 NFS 存储支持的持久卷（PV）和持久卷声明（PVC）。因此，要安装 NFS 子目录外部配置程序，首先使用以下命令集安装 helm：$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 $ chmod 700 get_helm.sh $ ./get_helm.sh 运行以下命令来启用 helm 仓库：$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner 使用以下 helm 命令部署配置程序：$ helm install -n nfs-provisioning --create-namespace nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --set nfs.server=192.168.1.139 --set nfs.path=/opt/dynamic-storage 上面的 helm 命令将自动创建 nfs-provisioning 命名空间，并安装 NFS 配置程序的容器荚/部署、名称为 nfs-client 的存储类，并将创建所需的 rbac。$ kubectl get all -n nfs-provisioning $ kubectl get sc -n nfs-provisioning 完美，上面的输出确认了配置程序容器荚和存储类已成功创建。步骤 3、创建持久卷声明（PVC）让我们创建 PVC 来为你的容器荚或部署请求存储。PVC 将从存储类 nfs-client 请求特定数量的存储：$ vi demo-pvc.yml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: demo-claim namespace: nfs-provisioning spec: storageClassName: nfs-client accessModes: - ReadWriteMany resources: requests: storage: 10Mi 保存并关闭文件。运行以下 kubectl 命令以使用上面创建的 YML 文件创建 PVC：$ kubectl create -f demo-pvc.yml 验证 PVC 和 PV 是否创建：$ kubectl get pv,pvc -n nfs-provisioning 太好了，上面的输出表明 PV 和 PVC 创建成功。步骤 4、测试并验证动态 NFS 配置为了测试和验证动态 NFS 配置，请使用以下 YML 文件启动测试容器荚：$ vi test-pod.yml kind: Pod apiVersion: v1 metadata: name: test-pod namespace: nfs-provisioning spec: containers: - name: test-pod image: busybox:latest command: - "/bin/sh" args: - "-c" - "touch /mnt/SUCCESS && sleep 600" volumeMounts: - name: nfs-pvc mountPath: "/mnt" restartPolicy: "Never" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: demo-claim 使用以下 kubectl 命令部署容器荚：$ kubectl create -f test-pod.yml 验证 test-pod 的状态：$ kubectl get pods -n nfs-provisioning 登录到容器荚并验证 NFS 卷是否已安装。$ kubectl exec -it test-pod -n nfs-provisioning /bin/sh 太棒了，上面容器荚的输出确认了动态 NFS 卷已安装且可访问。最后删除容器荚和 PVC，查看 PV 是否自动删除。$ kubectl delete -f test-pod.yml $ kubectl delete -f demo-pvc.yml $ kubectl get pv,pvc -n nfs-provisioning 这就是这篇文章的全部内容，希望对你有所帮助。请随时在下面的评论部分发表你的疑问和反馈。（题图：MJ/75dae36f-ff68-4c63-81e8-281e2c239356）via: https://www.linuxtechi.com/dynamic-nfs-provisioning-kubernetes/作者：Pradeep Kumar 选题：lkxed 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
当我第一次知道 DNS 时，我想它应该不会很复杂。不就是一些存储在服务器上的 DNS 记录罢了。有什么大不了的？但是教科书上只是介绍了 DNS 的原理，并没有告诉你实际使用中 DNS 可能会以多少种方式破坏你的系统。这可不仅仅是缓存问题！所以我 在 Twitter 上发起了一个提问，征集人们遇到的 DNS 问题，尤其是那些一开始看起来与 DNS 没什么关系的问题。（“总是 DNS 问题”这个梗）我不打算在这篇文章中讨论如何解决或避免这些问题，但我会放一些讨论这些问题的链接，在那里可以找到解决问题的方法。问题：网络请求缓慢如果你的网络比预期的要慢，这是因为某些原因导致 DNS 解析器变慢了。这可能是解析器负载过大或者存在内存泄漏等原因导致的。我的路由器的 DNS 转发器曾遇到过这个问题，导致我的所有 DNS 请求很慢。我通过重启路由器解决了这个问题。问题：DNS 超时一些网友提到由于 DNS 查询超时，他们的网络请求需要耗时 2 秒多甚至 30 秒。这跟“网络请求缓慢”问题类似，但情况要更糟糕，因为 DNS 请求就会消耗掉几秒钟时间。Sophie Haskins 有一篇关于 Kubernete DNS 超时的博客文章 一次 Kube DNS 踩坑经历。问题：ndots 设置一些网友提到在 /etc/resolv.conf 中设置 ndots:5 时会出现问题。下面是从 这篇《Kubernetes 容器荚中 /etc/resolv.conf 里设置 ndots:5 为什么会拖慢你的程序性能》中引用的 /etc/resolv.conf文件。 nameserver 100.64.0.10 search namespace.svc.cluster.local svc.cluster.local cluster.local eu-west-1.compute.internal options ndots:5 如果你用上面的配置文件，想要查询得域名是 google.com，那么你的程序会调用 getaddrinfo 函数，而它会依次查询以下域名：google.com.namespace.svc.cluster.local.google.com.svc.cluster.local.google.com.cluster.local.google.com.eu-west-1.compute.internal.google.com.简单来说，它会检查 google.com 是不是 search 这一行中的某个子域名。所以每发起一次 DNS 查询，你都得先等待前 4 次查询失败后才能获取到最终查询结果。问题：难以判断系统使用的 DNS 解析器这本身并不是一个问题，但当你遇到 DNS 问题时，一般都会跟 DNS 解析器有关。我没有一种判断 DNS 解析器的万能方法。下面是我知道的方法：在 Linux 系统上，最常见的是通过 /etc/resolv.conf 来选择 DNS 解析器。但是也有例外，比如浏览器可能会忽略 /etc/resolv.conf，而是使用 基于 HTTPS 的 DNS DNS-over-HTTPS 服务。如果你使用的是 UDP DNS，你可以通过 sudo tcpdump port 53 来查看 DNS 请求被发送到了哪里。但如果你使用的是基于 HTTPS 的 DNS 或 基于 TLS 的 DNS DNS over TLS ，这个方法就不行了。我依稀记得这在 MacOS 系统上会更加令人迷惑，我也不清楚原因。问题：DNS 服务器返回 NXDOMAIN 而不是 NOERROR这是我曾经遇到过的一个 Nginx 不能解析域名的问题。我设置 Nginx 使用一个特定的 DNS 服务器来解析 DNS 查询当访问这个域名时，Nginx 做了两次查询，第一次是对 A 的，第二次是对 AAAA 的对于 A 的查询，DNS 服务器返回 NXDOMAINNginx 认为这个域名不存在，然后放弃查询对于 AAAA 的查询 DNS 服务器返回了成功但 Nginx 忽略了对 AAAA 返回的查询结果，因为它前面已经放弃查询了问题出在 DNS 服务器本应该返回 NOERROR 的——那个域名确实存在，只是没有关于 A 的记录罢了。我报告了这个问题，然后他们修复了这个问题。我自己也写出过这个问题，所以我理解为什么会发生这种情况——很容易想当然地认为“没有要查询的记录，就应该返回 NXDOMAIN 错误码”。问题：自动生效的 DNS 缓存如果你在生成一个域名的 DNS 记录之前就访问这个域名，那么这个记录的缺失会被缓存起来。当你第一次遇到这个问题时一定会非常吃惊——我也是去年才知道有这个问题。缓存的 TTL 就是域名的 起始权限记录 Start of Authority （SOA） 记录的 TTL ——比如对于 jvns.ca ，这个值是一个小时。问题：Nginx 永久缓存 DNS 记录如果你在 Nginx 中使用下面的配置： location / { proxy_pass https://some.domain.com; } Nginx 只会在启动的时候解析一次 some.domain.com，以后不会再对其进行解析。这是非常危险的操作，尤其是对于那些 IP 地址经常变动的域名。它可能平安无事地运行几个月，然后突然在某个凌晨两点把你从床上纠起来。针对这个问题已经有很多众所周知的方法了，但由于本文不是关于 Nginx 的，所以我不打算深入探讨它。但你第一次遇到它时一定会很惊讶。这是一篇关于这个问题发生在 AWS 负载均衡器上的 博客文章。问题：Java 永久缓存 DNS 记录跟上面类似的问题，只是出现在 Java 上：据说 这与你 Java 的配置有关。“JVM 的默认 TTL 设置可能会导致只有 JVM 重启时才会刷新 DNS 记录。”我还没有遇到过这个问题，不过我那些经常写 Java 的朋友遇到过这个问题。当然，任何软件都可能存在永久缓存 DNS 的问题，但据我所知它经常出现在 Nginx 和 Java 上。问题：被遗忘的 /etc/hosts 记录这是另一种缓存问题：/etc/hosts 中的记录会覆盖你的常规 DNS 设置！让人迷惑的是 dig 命令会忽略 /etc/hosts 文件。所以当你使用 dig whatever.com 来查询 DNS 信息时，它会告诉你一切正常。问题：电子邮件未发送 / 将成为垃圾邮件电子邮件是通过 DNS（MX 记录, SPF 记录, DKIM 记录）来发送和验证的，所以有些电子邮件问题其实是 DNS 问题。问题：对国际化域名无效你可以使用非 ASCII 字符甚至是表情符来注册域名，比如 拉屎网 https://?.la。DNS 能够处理国际化域名是因为 ?.la 会被用 punycode 编码将转换为 xn--ls8h.la。尽管已经有了 DNS 处理国际化域名的标准，很多软件并不能很好地处理国际化域名。Julian Squires 的 干掉 Chrome 浏览器的表情符！！ 就是一个非常有趣的例子。问题：TCP DNS 被防火墙拦截有人提到一些防火墙会允许在 53 端口上使用 UDP 协议，但是禁止 TCP 协议。然而很多 DNS 查询需要在 53 端口上使用 TCP，这可能会导致很难排查的间歇性的问题。问题：musl 不支持 TCP DNS很多应用程序使用 libc 的 getaddrinfo 来做 DNS 查询。musl 是用在 Alpine Docker 容器上的 glibc 替代品。而它不支持 TCP DNS。如果你的 DNS 查询的响应数据超过 DNS UDP 数据包的大小（512 字节）就会出现问题。我对此仍然不太清楚，我下面我的理解也可能是错的:musl 的 getaddrinfo 发起一个 DNS 请求DNS 服务器发现请求的响应数据太大了，没法放入一个 DNS 数据包中DNS 服务器返回一个 空截断响应 empty truncated response ，并期望客户端通过 TCP DNS 重新用发起查询但 musl 不支持 TCP DNS，所以根本不会重试关于这个问题的文章：在 Alpine Linux 上的 DNS 解析问题。问题：getaddrinfo 不支持轮询 DNS 轮询 round robin DNS 是一种 负载均衡 load balancing 技术，每次 DNS 查询都会获得一个不同的 IP 地址。显然如果你使用 gethostbyname 做 DNS 查询不会有任何问题，但是用 getaddrinfo 就不行了。因为 getaddrinfo 会对获得的 IP 地址进行排序。在你从 gethostbyname 切换到 getaddrinfo 时可能完全不会意识到这可能会引起负载均衡问题。这个问题可能会非常隐蔽，如果你不是用 C 语言编程的话，这些函数调用被隐藏在各种调用库背后，你可能完全意识不到发生了这种改变。所以某次看似人畜无害的升级就可能导致你的 DNS 负载均衡失效。下面是讨论这个的一些文章：getaddrinfo 导致轮询 DNS 失效getaddrinfo，轮询 DNS 和 happy eyeballs 算法问题：启动服务时的竞争条件有人 提到 使用 Kubernete DNS 时遇到的问题：他们有两个同时启动的容器，一旦启动就会立即尝试解析对方的地址。由于 Kubernete DNS 还没有改变，所以 DNS 查询会失败。这个失败会被缓存起来，所以后续的查询会一直失败。写在最后我所列举的不过是 DNS 问题的冰山一角，期待大家告诉我那些我没有提到的问题和相关链接。我希望了解这些问题在实际中是如何发生的以及如何被解决的。（题图：MJ/f512f18e-2e1d-4614-bed1-b0a0c373e14d）via: https://jvns.ca/blog/2022/01/15/some-ways-dns-can-break/作者：Julia Evans 选题：lujun9972 译者：toknow-gh 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出