分类 技术 下的文章

FreeIPA 是一个强大的开源身份管理系统,提供集中的身份验证、授权和计费服务。在本文中,我们将逐步介绍在 Ubuntu 22.04 / 20.04 上配置 FreeIPA 客户端的步骤。配置 FreeIPA 客户端后,我们将尝试使用在 FreeIPA 服务器上创建的用户登录。

在我们之前的帖子中,我们已经讨论了 FreeIPA 服务器在 RHEL8/Rokcy Linux 8/ AlmaLinux 8 上的安装步骤。

在 FreeIPA 服务器上创建用户进行集中认证

登录到你的 FreeIPA 服务器并创建一个名为 sysadm 的用户,运行以下命令:

$ sudo kinit admin
Password for [email protected]:
$
$ sudo ipa config-mod --defaultshell=/bin/bash
$ sudo ipa user-add sysadm --first=System --last=Admin --password
Password:
Enter Password again to verify:
-------------------
Added user "sysadm"
-------------------
User login: sysadm
First name: System
Last name: Admin
Full name: System Admin
Display name: System Admin
Initials: SA
Home directory: /home/sysadm
GECOS: System Admin
Login shell: /bin/bash
Principal name: [email protected]
Principal alias: [email protected]
User password expiration: 20230415073041Z
Email address: [email protected]
UID: 464600003
GID: 464600003
Password: True
Member of groups: ipausers
Kerberos keys available: True
$

第一个命令是获取 Kerberos 凭证,第二个命令将所有用户的默认登录 shell 设置为 /bin/bash,第三个命令用于创建名为 sysadm 的用户。

在 Ubuntu 22.04 /20.04 上配置 FreeIPA 客户端的步骤

执行以下步骤来配置 FreeIPA 客户端以进行集中身份验证。

1、在 FreeIPA 服务器上添加 Ubuntu 系统的 DNS 记录

登录到你的 FreeIPA 服务器并运行以下命令为 FreeIPA 客户端(即 Ubuntu 22.04/20.04)添加 DNS 记录:

$ sudo ipa dnsrecord-add linuxtechi.lan app01.linuxtechi.lan --a-rec 192.168.1.106
  Record name: app01.linuxtechi.lan
  A record: 192.168.1.106
$

在上面的命令中,app01.linuxtechi.lan 是我的 Ubuntu 系统,IP 地址为 192.168.1.106

注意:确保你的 FreeIPA 服务器和客户端处于同一时区并从 NTP 服务器获取时间。

2、安装 FreeIPA 客户端包

从你的 Ubuntu 系统运行以下命令以安装 freeipa-client 以及依赖项:

$ sudo apt install freeipa-client oddjob-mkhomedir -y

在安装 freeipa-client 时,我们将看到以下页面,选择确定并回车。

在下一个屏幕中,按回车键跳过。

3、在主机文件中添加 FreeIPA 服务器 IP 和主机名

/etc/hosts 文件中添加以下 FreeIPA 服务器条目:

$ echo "192.168.1.102 ipa.linuxtechi.lan ipa" | sudo tee -a /etc/hosts
$ echo "192.168.1.106 app01.linuxtechi.lan app01" | sudo tee -a /etc/hosts

更改适合你的设置的 IP 地址和主机名。

4、使用 ipa-client-install 配置 FreeIPA 客户端

现在运行以下 ipa-client-install 命令在你的 Ubuntu 系统上配置 FreeIPA 客户端:

$ sudo ipa-client-install --hostname=`hostname -f` --mkhomedir --server=ipa.linuxtechi.lan --domain linuxtechi.lan --realm LINUXTECHI.LAN

更改适合你设置的 FreeIPA 服务器地址、域名和领域。

上述命令的输出如下所示:

完美,上面的输出确认 FreeIPA 客户端安装成功。

现在允许在用户首次使用 FreeIPA 服务器进行身份验证时自动创建用户的主目录。

在文件 /usr/share/pam-configs/mkhomedir 中添加以下行:

required pam_mkhomedir.so umask=0022 skel=/etc/skel
$ echo "required pam_mkhomedir.so umask=0022 skel=/etc/skel" | sudo tee -a /usr/share/pam-configs/mkhomedir

要使上述更改生效,请运行以下命令:

$ sudo pam-auth-update

选择确定,然后按回车键。

5、尝试使用 sysadm 用户登录到你的 Ubuntu 系统

尝试使用 sysadm 用户通过 SSH 登录到你的 Ubuntu 系统,

$ ssh [email protected]

正如你在上面看到的,当我们第一次登录时,它说密码已过期。它将提示我们设置新密码并断开会话。

更新密码后,尝试 SSH 登录 Ubuntu 系统,这次我们应该可以登录了。

$ ssh [email protected]

输出:

太好了,上面的输出确认我们已经使用集中用户成功登录到我们的 Ubuntu 系统。这也说明我们已经成功配置了 FreeIPA 客户端。

如果你想从 ubuntu 系统中卸载 FreeIPA,然后运行以下命令集:

$ sudo ipa-client-install --uninstall
$ sudo  rm -rf /var/lib/sss/db/*
$ sudo systemctl restart sssd.service

以上就是这篇文章的全部内容,我相信你已经发现它提供了很多信息。请在下面发表你的疑问和反馈。

(题图:MJ/bd5b7777-f70a-4367-ac78-d026792b855a)


via: https://www.linuxtechi.com/configure-freeipa-client-on-ubuntu/

作者:Pradeep Kumar 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Rust 和 Python 的优势互补。可以使用 Python 进行原型设计,然后将性能瓶颈转移到 Rust 上。

Python 和 Rust 是非常不同的语言,但它们实际上非常搭配。但在讨论如何将 Python 与 Rust 结合之前,我想先介绍一下 Rust 本身。你可能已经听说了这种语言,但可能还没有了解过它的细节。

什么是 Rust?

Rust 是一种低级语言,这意味着程序员所处理的东西接近于计算机的 “真实” 运行方式。

例如,整数类型由字节大小定义,与 CPU 支持的类型相对应。虽然我们很想简单地说 Rust 中的 a+b 对应于一条机器指令,但实际上并不完全是这样!

Rust 编译器链非常复杂。作为第一种近似的方法,将这样的语句视为 “有点” 真实是有用的。

Rust 旨在实现零成本抽象,这意味着许多语言级别可用的抽象在运行时环境中会被编译去掉。

例如,除非明确要求,对象会在堆栈上分配。结果是,在 Rust 中创建本地对象没有运行时成本(尽管可能需要进行初始化)。

最后,Rust 是一种内存安全的语言。也有其他内存安全的语言和其他支持零成本抽象的语言。但通常这些是两类不同的语言。

内存安全并不意味着不可能在 Rust 中出现内存违规。它确实意味着只有两种方式可能导致内存违规:

  • 编译器的错误。
  • 显式声明为不安全(unsafe)的代码。

Rust 标准库代码有很多被标记为不安全的代码,虽然比许多人预期的少。这并不意味着该语句无意义。除了需要自己编写不安全代码的(罕见的)情况外,内存违规通常是由基础设施造成的。

为什么会有 Rust 出现?

为什么人们要创建 Rust?是哪些问题没有被现有编程语言解决吗?

Rust 被设计成既能高效运行,又保证内存安全。在现代的联网世界中,这是一个越来越重要的问题。

Rust 的典型应用场景是协议的低级解析。待解析的数据通常来自不受信任的来源,并且需要通过高效的方式进行解析。

如果你认为这听起来像 Web 浏览器所做的事情,那不是巧合。Rust 最初起源于 Mozilla 基金会,它是为了改进 Firefox 浏览器而设计的。

如今,需要保证安全和速度的不仅仅是浏览器。即使是常见的微服务架构也必须能够快速解析不受信任的数据,同时保证安全。

现实示例:统计字符

为了理解 “封装 Rust” 的例子,需要解决一个问题。这个问题需要满足以下要求:

  • 足够容易解决。
  • 能够写高性能循环来优化。
  • 有一定的现实意义。

这个玩具问题的例子是判断一个字符在一个字符串中是否出现超过了 X 次。这个问题不容易通过高效的正则表达式解决。即使是专门的 Numpy 代码也可能不够快,因为通常没有必要扫描整个字符串。

你可以想象一些 Python 库和技巧的组合来解决这个问题。然而,如果在低级别的语言中实现直接的算法,它会非常快,并且更易于阅读。

为了使问题稍微有趣一些,以演示 Rust 的一些有趣部分,这个问题增加了一些变化。该算法支持在换行符处重置计数(意即:字符是否在一行中出现了超过 X 次?)或在空格处重置计数(意即:字符是否在单词中出现了超过 X 次?)。

这是唯一与 “现实性” 相关的部分。过多的现实性将使这个示例在教育上不再有用。

支持枚举

Rust 支持使用枚举(enum)。你可以使用枚举做很多有趣的事情。

目前,只使用了一个简单的三选一的枚举,并没有其他的变形。这个枚举编码了哪种字符重置计数。

#[derive(Copy)]
enum Reset {
    NewlinesReset,
    SpacesReset,
    NoReset,
}

支持结构

接下来的 Rust 组件更大一些:这是一个结构(struct)。Rust 的结构与 Python 的 dataclass 有些相似。同样,你可以用结构做更复杂的事情。

#[pyclass]
struct Counter {
    what: char,
    min_number: u64,
    reset: Reset, 
}

实现块

你可以在 Rust 中使用一个单独的块,称为实现(impl)块,为结构添加一个方法。但具体细节超出了本文的范围。

在这个示例中,该方法调用了一个外部函数。这主要是为了分解代码。更复杂的用例将指示 Rust 编译器内联该函数,以便在不产生任何运行时成本的情况下提高可读性。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64, reset: Reset) -> Self {
        Counter{what: what, min_number: min_number, reset: reset}
    }
    
    fn has_count(
        &self,
        data: &str,
    ) -> bool {
        has_count(self, data.chars())
    }
}

函数

默认情况下,Rust 变量是常量。由于当前的计数(current_count)必须更改,因此它被声明为可变变量。

fn has_count(cntr: &Counter, chars: std::str::Chars) -> bool {
    let mut current_count : u64 = 0;
    for c in chars {
        if got_count(cntr, c, &mut current_count) {
            return true;
        }
    }
    false
}

该循环遍历字符并调用 got_count 函数。再次强调,这是为了将代码分解成幻灯片展示。它展示了如何向函数发送可变引用。

尽管 current_count 是可变的,但发送和接收站点都显式标记该引用为可变。这可以清楚地表明哪些函数可能修改一个值。

计数

got_count 函数重置计数器,将其递增,然后检查它。Rust 的冒号分隔的表达式序列评估最后一个表达式的结果,即是否达到了指定的阈值。

fn got_count(cntr: &Counter, c: char, current_count: &mut u64) -> bool {
    maybe_reset(cntr, c, current_count);
    maybe_incr(cntr, c, current_count);
    *current_count >= cntr.min_number
}

重置代码

reset 的代码展示了 Rust 中另一个有用的功能:模式匹配。对 Rust 中匹配的完整描述需要一个学期级别的课程,不适合在一个无关的演讲中讲解。这个示例匹配了该元组的两个选项之一。

fn maybe_reset(cntr: &Counter, c: char, current_count: &mut u64) -> () {
    match (c, cntr.reset) {
        ('\n', Reset::NewlinesReset) | (' ', Reset::SpacesReset)=> {
            *current_count = 0;
        }
        _ => {}
    };
}

增量支持

增量将字符与所需字符进行比较,并在匹配时增加计数。

fn maybe_incr(cntr: &Counter, c: char, current_count: &mut u64) -> (){
    if c == cntr.what {
        *current_count += 1;
    };
}

请注意,我在本文中优化了代码以适合幻灯片。这不一定是 Rust 代码的最佳实践示例,也不是如何设计良好的 API 的示例。

为 Python 封装 Rust 代码

为了将 Rust 代码封装到 Python 中,你可以使用 PyO3。PyO3 Rust “crate”(即库)允许内联提示将 Rust 代码包装为 Python,使得修改两者更容易。

包含 PyO3 crate 原语

首先,你必须包含 PyO3 crate 原语。

use pyo3::prelude::*;

封装枚举

枚举需要被封装。derive 从句对于将枚举封装为 PyO3 是必需的,因为它们允许类被复制和克隆,使它们更容易在 Python 中使用。

#[pyclass]
#[derive(Clone)]
#[derive(Copy)]
enum Reset {
    /* ... */
}

封装结构

结构同样需要被封装。在 Rust 中,这些被称为 “宏”,它们会生成所需的接口位。

#[pyclass]
struct Counter {
    /* ... */
}

封装实现

封装实现(impl)更有趣。增加了另一个名为 new 的宏。此方法被标记为 #[new],让 PyO3 知道如何为内置对象公开构造函数。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64,
          reset: Reset) -> Self {
        Counter{what: what,
          min_number: min_number, reset: reset}
    }
    /* ... */
}

定义模块

最后,定义一个初始化模块的函数。此函数具有特定的签名,必须与模块同名,并用 #[pymodule] 修饰。

#[pymodule]
fn counter(_py: Python, m: &PyModule
) -> PyResult<()> {
    m.add_class::<Counter>()?;
    m.add_class::<Reset>()?;
    Ok(())
}

? 显示此函数可能失败(例如,如果类没有正确配置)。 PyResult 在导入时转换为 Python 异常。

Maturin 开发

为了快速检查,用 maturin develop 构建并将库安装到当前虚拟环境中。这有助于快速迭代。

$ maturin develop

Maturin 构建

maturin build 命令构建一个 manylinux 轮子,它可以上传到 PyPI。轮子是特定于 CPU 架构的。

Python 库

从 Python 中使用库是最简单的部分。没有任何东西表明这与在 Python 中编写代码有什么区别。这其中的一个有用方面是,如果你优化了已经有单元测试的 Python 中的现有库,你可以使用 Python 单元测试来测试 Rust 库。

导入

无论你是使用 maturin develop 还是 pip install 来安装它,导入库都是使用 import 完成的。

import counter

构造函数

构造函数的定义正好使对象可以从 Python 构建。这并不总是如此。有时仅从更复杂的函数返回对象。

cntr = counter.Counter(
    'c',
    3,
    counter.Reset.NewlinesReset,
)

调用函数

最终的收益终于来了。检查这个字符串是否至少有三个 “c” 字符:

>>> cntr.has_count("hello-c-c-c-goodbye")
True

添加一个换行符会触发剩余操作,这里没有插入换行符的三个 “c” 字符:

>>> cntr.has_count("hello-c-c-\nc-goodbye")
False

使用 Rust 和 Python 很容易

我的目标是让你相信将 Rust 和 Python 结合起来很简单。我编写了一些“粘合剂”代码。Rust 和 Python 具有互补的优点和缺点。

Rust 非常适合高性能、安全的代码。Rust 具有陡峭的学习曲线,对于快速原型解决方案而言可能有些笨拙。

Python 很容易入手,并支持非常紧密的迭代循环。Python 确实有一个“速度上限”。超过一定程度后,从 Python 中获得更好的性能就更难了。

将它们结合起来完美无缝。在 Python 中进行原型设计,并将性能瓶颈移至 Rust 中。

使用 Maturin,你的开发和部署流程更容易进行。开发、构建并享受这一组合吧!


via: https://opensource.com/article/23/3/python-loves-rust

作者:Moshe Zadka 选题:lkxed 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在本指南中,我们演示了如何在 Rocky Linux 9 / Alma Linux 9 上安装 KVM。

KVM 是 内核虚拟机 Kernel Virtualization Machine 的简称,是一个为 Linux 内核设计的开源虚拟化平台。它是一种 1 类管理程序,或通常称为裸机管理程序。它允许用户创建和管理多台客户机,这些可以在 Linux 或 Windows 操作系统中创建。

与大多数虚拟化平台一样,它将硬件资源(如 CPU、内存、存储、网络、图形等)抽象化,并将它们分配给独立于宿主机运行的客户机。

先决条件

  • 预装 Rocky Linux 9 / AlmaLinux 9
  • 具有管理员权限的 sudo 用户
  • 互联网连接

1、验证是否启用了硬件虚拟化

首先,你需要验证你的系统是否启用了虚拟化功能。在大多数现代系统上,此功能已在 BIOS 中启用。但可以肯定的是,你可以验证是否如图所示启用了虚拟化。

该命令探测是否存在 VMX( 虚拟机扩展 Virtual Machine Extension ),它是英特尔硬件虚拟化的 CPU 标志,或 SVM,它是 AMD 硬件虚拟化的标志。

$ cat /proc/cpuinfo | egrep "vmx|svm"

从以下输出中,你可以看到我们的系统启用了英特尔硬件虚拟化:

2、在 Rocky Linux 9 / AlmaLinux 9 上安装 KVM

确保启用虚拟化后,下一步就是安装 KVM 和管理工具。为此,请运行以下 dnf 命令。

$ sudo dnf install qemu-kvm virt-manager libvirt virt-install virt-viewer virt-top bridge-utils  bridge-utils virt-top libguestfs-tools -y

安装完成后,运行以下命令检查是否已加载所需的 KVM 模块。

$ lsmod | grep kvm

你应该得到以下输出以确认已加载必要的模块:

3、启动并启用 libvirtd 守护进程

在下一步中,一定要启动 libvirtd 守护进程。这是一个服务器端守护程序组件,可在虚拟化的客户机上运行和管理任务。它用于管理虚拟化技术,例如 Xen、KVM 和 ESXi 等等。

要启动 libvirtd 守护进程,请运行以下命令:

$ sudo systemctl start libvirtd

请务必启用该服务以在引导时启动:

$ sudo systemctl enable --now libvirtd

验证 libvirtd 守护进程是否正在运行,如下所示:

$ sudo systemctl status libvirtd

4、设置桥接接口

到目前为止,我们已经安装了 KVM 和所有管理工具,事实上,我们可以继续启动虚拟机。但是,如果我们可以从管理程序网络外部访问虚拟机,那就太好了。为此,我们需要创建一个桥接接口。

首先,确定系统上的网络接口。

$ sudo nmcli connection show

从输出来看,ens160 是活动的网络接口,请务必注意你的情况下的接口,因为你将一路使用它。

要开始创建网桥,首先,使用以下语法用其 UUID 删除连接:

$ sudo nmcli connection delete UUID

在我们的例子中,命令将是:

$ sudo nmcli connection delete 19e98123-9a84-30a6-bc59-a7134446bb26

你将收到连接已成功删除的确认信息。

在继续进行之前,最好准备好以下详细信息:

  • 网桥名称 – 新网桥的首选名称(例如 br1
  • 设备名称 – 这是你的网络接口的名称。它将作为网桥的从属设备(例如,ens160
  • IP 地址/子网 – 桥接网络的 IP 地址和子网(例如 192.168.2.50/24)。请注意,这应该与你的网络子网和 IP 地址相对应。
  • 网关 – 你网络的默认网关地址(例如 192.168.2.1
  • DNS1 和 DNS2 – 首选 DNS 地址(例如 8.8.8.88.8.4.4

继续,使用以下语法创建一个新的桥接接口。

$ sudo nmcli connection add type bridge autoconnect yes con-name BRIDGE NAME ifname BRIDGE NAME

在我们的例子中,br1 是首选的网桥接口名称。因此,命令将如图所示:

$ sudo nmcli connection add type bridge autoconnect yes con-name br1 ifname br1

在接下来的步骤中,你将通过指定 IP 子网、网关和 DNS 值来修改网桥。

首先使用以下语法指定 IP 子网:

$ sudo nmcli connection modify BRIDGE NAME ipv4.addresses IP ADDRESS/SUBNET ipv4.method manual

根据我们的设置,命令将是:

$ sudo nmcli connection modify br1 ipv4.addresses 192.168.2.150/24 ipv4.method manual

接下来,使用以下语法指定网关地址:

$ sudo nmcli connection modify BRIDGE NAME ipv4.gateway GATEWAY

根据我们的网络,该命令采用以下格式:

$ sudo nmcli connection modify br1 ipv4.gateway 192.168.2.1

DNS 地址的语法如下:

$ sudo nmcli connection modify BRIDGE NAME ipv4.dns DNS1 +ipv4.dns DNS2

该命令采用以下格式:

$ sudo nmcli connection modify br1 ipv4.dns 8.8.8.8 +ipv4.dns 8.8.4.4

此后,使用以下命令添加网桥从属设备:

$ sudo nmcli connection add type bridge-slave autoconnect yes con-name DEVICE NAME ifname DEVICE NAME master BRIDGE NAME

使用我们的值,命令如图所示:

$ sudo nmcli connection add type bridge-slave autoconnect yes con-name ens160 ifname ens160 master br1

你将收到以下确认信息,表明已成功添加网桥从属设备。请记住,桥接从属设备是你的网络接口或适配器。

要确认网桥已创建,请运行以下命令:

$ sudo nmcli connection show

从输出中,你可以看到列出了网桥接口。

激要活它,请运行以下命令:

$ sudo nmcli connection up br1

此外,你可以使用 ip addr 命令验证:

$ ip addr | grep br1

最后,编辑网桥配置文件。

$ sudo vi /etc/qemu-kvm/bridge.conf

添加以下行:

allow all

然后重新启动虚拟化守护进程以应用更改

$ sudo systemctl restart libvirtd

5、创建虚拟机

安装 KVM 并配置桥接连接后,现在让我们创建一个虚拟机。在执行之前,为登录用户分配必要的所有权,以便在不切换到 root 的情况下运行命令。

$ sudo chown -R $USER:libvirt /var/lib/libvirt/

在命令行上,我们将使用以下语法使用 Ubuntu 20.04 ISO 镜像创建虚拟机。

$ virt-install \
    --name Ubuntu \
    --ram 2048 \
    --vcpus 2 \
    --disk path=/var/lib/libvirt/images/ubuntu-20.04.img,size=15 \
    --os-variant ubuntu20.04 \
    --network bridge=br1,model=virtio \
    --graphics vnc,listen=0.0.0.0 \
    --console pty,target_type=serial \
    --cdrom /home/linuxtechi/Downloads/ubuntu-20.04.4-desktop-amd64.iso

执行该命令后,将启动图形屏幕会话,并开始安装客户操作系统。

总结

我们关于如何在 Rocky Linux 9 / AlmaLinux 9 上安装 KVM 的文章到此结束,非常欢迎你提供反馈。

(题图:MJ/a364d6e3-0c59-4be8-bf02-5df078359429)


via: https://www.linuxtechi.com/install-kvm-on-rocky-linux-almalinux/

作者:Pradeep Kumar 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

不可变性是一种时下流行的概念。看看有哪些适合你的不可变 Linux 发行版。

每个发行版都是根据一系列目的而定制的。一些配置适用于 旧计算机,一些旨在提供 优质的用户体验,而一些则专注于安全性。

几年前,不可变发行版不是用户想要的。但是,最近越来越多的项目正在将不可变性作为 Linux 发行版的核心特征。

为什么会这样?有哪些可供选择?在你查看此列表之前,让我简要地向你介绍不可变性的更多内容:

什么是不可变 Linux 发行版?

不可变发行版确保操作系统的核心保持不变。对于不可变发行版来说,根文件系统保持为只读状态使得它可以在多个实例中保持相同。当然,如果你希望更改某些内容,则仍可以进行更改。但默认情况下该能力会被禁用。

它有什么用处?

传统上,不可变发行版存在的目的是为了方便测试和基于容器的软件开发。此外,不可变性为你的操作系统提供了更好的安全性和可靠的更新。

早期,这种特性的关注点主要集中在针对专业人士和开发人员的发行版上。现在,它开始应用于日常桌面用户。

? 以下列表并没有按照任何特定的排名顺序列出,并且某些发行版仍处于早期开发阶段。

1、carbonOS

carbon os screenshot with gnome menu

在写这篇文章时,carbonOS 是一款仍未推出的独立 Linux 发行版。它专注于提供强大的技术和流畅的用户体验。

它采用 Flatpak 优先和容器优先的方法。carbonOS 还旨在提供安全的系统更新,并提供一些不是所有原子发行版都具备的功能,如经过验证的启动。

除了其独特的特点外,它还希望专注于为用户提供出色的 GNOME 桌面体验。

2、Fedora Silverblue

fedora workstation screenshot

Silverblue 是具有不可变性的 Fedora Workstation 的变种,是最受欢迎的不可变发行版之一。

用户界面和体验与普通的 Fedora Workstation 发行版保持一致。每当有新的 Fedora 版本发布时,也会有一个新的 Silverblue 版本。

Fedora Silverblue 旨在提供稳定的体验,适用于测试和基于容器的软件开发。如果更新后出现问题,你总是可以回滚到该操作系统的先前版本。

3、Flatcar Container Linux

flatcar linux

正如名字所示,这是一个专门针对容器工作负载而定制的社区构建版 Linux 发行版。

你将获得一个最小化的操作系统镜像,其中仅包括运行容器所需的工具,没有包管理器,也无需配置。

如果你想为你的容器提供可靠的底层,那么 Flatcar 可能是一个不错的选择,因为它同时具有可伸缩性、安全性和简单性。请在其 GitHub 页面 上了解更多信息。

4、openSUSE MicroOS

opensuse microos

openSUSE MicroOS 是为需要部署容器或处理自动化工作流程的服务器而构建的。

它依赖于事务性更新(使用 Btrfs 进行快照),这有助于保存文件系统的历史记录而不占用太多存储空间。

总的来说,MicroOS 是服务器用户的一个可扩展、可靠和安全的选项。

5、Vanilla OS

vanilla os

Vanilla OS 是不可变性领域中的一个相对较新的参与者。但是,它在发布后成功引起了轰动,并在第一个稳定版发布后切换到了以 Debian 为基础,放弃了 Ubuntu。

它旨在提供易于使用的桌面体验,同时具备可靠性和不可变性特征。

6、Bottlerocket

Bottlerocket 是由 AWS 构建的基于 Linux 的开源操作系统,旨在在其平台上运行容器。

与其他选项不同,它的使用仅限于 AWS。

它确保使用 AWS 服务的客户具有最少的维护开销,并且可以无缝地自动化其工作流程。创建 EC2( 亚马逊弹性计算云 Amazon Elastic Compute Cloud )时,你只能将其用作 AMI( 亚马逊机器镜像 Amazon Machine Image ) 使用。

7、blendOS

blendOS

blendOS 是一个正在开发中的有趣发行版,旨在提供其他发行版的各种优点。

换句话说,你可以在发行版上安装任何类型的软件包(RPM、DEB 等),同时获得所期望的不可变性和更新可靠性。

8、Talos Linux

talos linux

另一个独特的 Linux 发行版,专为 Kubernetes 设计。Talos Linux 对于云用户/开发人员来说是一个有趣的选择。

它是安全、不可变的,是支持云平台、裸机和虚拟化平台的最小化选择之一。你还可以在 Docker 中轻松启动 Talos 集群。

该操作系统从 SquashFS 中运行在内存中,这样整个主磁盘都可以留给 Kubernetes。

9、NixOS

NixOS 是当前 最先进的 Linux 发行版 之一。如果你想要不可变性以及易于恢复、强大的软件包管理器等诸多好处,那么 NixOS 将是一个很好的选择。

如果你还不了解 NixOS,也不用担心,可以浏览我们的 NixOS 系列文章 来学习并进行设置。

10、GUIX

GUIX 类似于 NixOS(某种程度上),并且专为希望获得可靠升级和良好系统控制的高级用户而设计。

如果你是一名新的 Linux 用户,不应将其视为你的日常操作系统。因此,你可能需要查阅 文档 以便浏览并开始使用。

11、Endless OS

Endless OS 是一个基于 Debian 的 Linux 发行版。

与其它基于 Debian 的发行版(例如 Ubuntu)不同,Endless OS 采用了健壮的设计,在其核心实现了不可变性,以确保更新一个软件包不会破坏系统。

? 你对不可变的 Linux 发行版有何看法?你需要它们吗?你是否想在未来将你系统上的流行选项替换为其中任何一个?

(题图:MJ/6c0169a0-9820-4bf7-b9fb-f0cd2c45d7bf)


via: https://itsfoss.com/immutable-linux-distros/

作者:Ankush Das 选题:lkxed 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

DHCP 是 “ 动态主机配置协议 Dynamic Host Configuration Protocol ” 的首字母缩写词,它是一种网络协议,可自动为计算机网络中的客户端系统分配 IP 地址。它从 DHCP 池或在其配置中指定的 IP 地址范围分配客户端。虽然你可以手动为客户端系统分配静态 IP,但 DHCP 服务器简化了这一过程,并为网络上的客户端系统动态分配 IP 地址。

在本文中,我们将演示如何在 RHEL 9 / Rocky Linux 9 上安装和配置 DHCP 服务器。

先决条件

  • 预装 RHEL 9 或 Rocky Linux 9
  • 具有 sudo 管理权限的普通用户
  • 本地配置的 YUM/DNF 仓库或 RHEL 9 的 Red Hat 订阅
  • 互联网连接

事不宜迟,让我们进入 DHCP 服务器安装步骤。

1、在 RHEL 9 / Rocky Linux 9 上配置静态 IP 地址

开始时,必须在 RHEL 或 Rocky Linux 系统上设置静态 IP 地址。有多种方法可以执行此操作,但最简单和最直观的方法是使用 nmtuinmcli 实用程序。

要确认你的 Linux 系统的 IP 地址,请运行以下 ip 命令:

$ ip a

2、安装和配置 DHCP 服务器

配置静态 IP 后,下一步就是安装 DHCP 服务器。RHEL 9 或 Rocky Linux 9 仓库 (BaseOS) 默认提供 dhcp-server 包,你可以如图所示安装它:

$ sudo dnf install dhcp-server -y

安装 dhcp 服务器后,我们需要进一步并配置设置。因此,打开 DHCP 配置文件:

$ sudo vi /etc/dhcp/dhcpd.conf

将以下代码行粘贴到配置文件中。请务必将子网配置为你的首选值:

default-lease-time 3600;
max-lease-time 86400;
authoritative;
subnet 192.168.10.0 netmask 255.255.255.0 {
    range 192.168.10.100 192.168.10.200;
    option routers 192.168.10.1;
    option subnet-mask 255.255.255.0;
    option domain-name-servers 192.168.10.1;
}

保存并关闭文件。

让我们看一下其中的一些值:

  • default-lease-time 值指定 DHCP 服务器将地址租给客户端的时间。在这种情况下,默认租用时间值为 3600 秒或 1 小时。
  • max-lease-time 是将 IP 租给客户端的最长持续时间。在我们的例子中,这被设置为 86400 秒或 24 小时。
  • 下一部分是子网配置。在此设置中,192.168.10.0 是子网,255.255.255.0 是子网掩码。IP 地址范围从 192.168.10.100 一直到 192.168.10.200
  • router 选项定义默认网关。在本例中为 192.168.10.1
  • subnet-mask 选项确定分配给每个客户端或主机的子网掩码。在本例中为 255.255.255.0
  • 最后,domain-name-servers 选项指定 DNS 服务器。在本例中为 192.168.10.1

完成后,保存更改并退出。然后启用并启动 DHCP 服务。

$ sudo systemctl enable --now dhcpd
$ sudo systemctl status dhcpd

请注意:

此时,DHCP 服务应该分发 IP 地址。如果你的 LAN 中有另一个 DHCP 服务器或路由器,关闭它以防止 IP 地址分配冲突是明智的。这将导致一些客户端从 RHEL 或 Rocky Linux 服务器上的 DHCP 服务器获得 IP 分配,而其余的则从路由器获得 IP 分配,这当然不是你想要发生的事情。因此,请记住关闭 LAN 设置中的任何其他 DHCP 服务器。

3、测试 DHCP 服务器安装

在我们模拟的 LAN 设置中,你可以看到 Ubuntu 系统已经从 RHEL 或 Rocky Linux DHCP 服务器中选择了一个 IP。

回到我们的 DHCP 服务器并在 /var/log/message 文件中搜索 Ubuntu 机器的 IP 地址:

$ sudo tail -50 /var/log/messages | grep -i 192.168.10.100

完美,上面的输出确认 Ubuntu 机器从我们的 DHCP 服务器获得了 IP 服务器。

结论

这篇文章到此结束。在本指南中,你学习了如何在 RHEL 9 / Rocky Linux 9 上安装和配置 DHCP 服务器。请在下面的评论部分发表你的疑问和反馈。

(题图:MJ/d396485d-963c-4d17-8c4b-f3c8e11dcc5d)


via: https://www.linuxtechi.com/configure-dhcp-server-on-rhel-rockylinux/

作者:Pradeep Kumar 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用一个简单的计数程序比较古老的 C 语言和现代的 Go 语言。

Go 是一种现代编程语言,它很大程度上源自于 C 编程语言。因此,对于写 C 程序的程序员来说,Go 应该会感觉很熟悉。Go 让编写新程序变得容易,同时让 C 程序员感觉熟悉,但避免了 C 编程语言的许多常见陷阱。

本文比较了一个简单的 C 和 Go 程序,该程序将数字从一相加到十。由于这个程序只使用了小的数值,所以结果不会变得太大,因此只使用了普通的整数变量。像这样的循环在编程中非常常见,所以这个简单的程序很容易比较 C 和 Go。

如何在 C 中执行循环

C 语言中最基本的循环是 for 循环,它允许你对一组值进行迭代。for 循环的基本语法是:

for (起始条件 ; 结束条件 ; 每次迭代后执行的操作) { 循环内要执行的内容 ; }

你可以编写一个 for 循环,以打印从 1 到 10 的数字,将起始条件设置为 count = 1,将结束条件设置为 count <= 10。这样就以 count 变量等于 1 时开始循环。结束条件意味着只要 count 变量小于或等于 10 ,循环就会继续。

每次迭代之后,你使用 count = count + 1count 变量的值增加 1。在循环内部,你可以使用 printf 打印 count 变量的值:

for (count = 1; count <= 10; count = count + 1) {
  printf("%d\n", count);
}

C 程序中常见的惯例是 ++,它表示 “将某个值加一”。如果你写 count++,那就相当于 count = count + 1。大多数 C 程序员会使用 count++ 来编写 for 循环中每次迭代后要执行的操作,像这样:

for (count = 1; count <= 10; count++) {
  printf("%d\n", count);
}

这是一个示例程序,将从 1 到 10 的数字相加,然后打印结果。使用 for 循环对数字进行迭代,但不要打印数字,而是将数字添加到 sum 变量中:

#include <stdio.h>

int main() {
  int sum;
  int count;
  puts("adding 1 to 10 ..");
  sum = 0;

  for (count = 1; count <= 10; count++) {
    sum = sum + count;
  }

这个程序使用了两个不同的 C 函数来向用户打印结果。puts 函数打印引号中的字符串。如果你需要打印纯文本,使用 puts 是个不错的选择。

printf 函数 使用特殊字符在格式字符串中打印格式化的输出。printf 函数可以打印许多不同种类的值。关键字 %d 打印十进制(整数)值。

如果你编译并运行这个程序,你会看到这个输出:

adding 1 to 10 ..
The sum is 55

如何在 Go 中执行循环

Go 提供了与 C 中非常相似的 for 循环。C 程序中的 for 循环可以直接转换为 Go 的 for 循环,并具有相似的表示形式:

for count = 1; count <= 10; count++ {
  fmt.Printf("%d\n", count)
}

使用这个循环,你可以直接转换为 Go 的示例程序:

package main
import "fmt"

func main() {
  var sum, count int
  fmt.Println("adding 1 to 10 ..")

  for count = 1; count <= 10; count++ {
    sum = sum + count
  }
  fmt.Printf("The sum is %d\n", sum)
}

虽然上述方式在 Go 中是正确的,但它并不是最常用的 Go 写法。采用惯例是“使用与本地语言为人所知的表达方式”。任何语言的目标都是高效的沟通,编程语言也不例外。在不同的编程语言之间进行转换时,重要的是意识到尽管物似而意不同,一种编程语言中的典型写法在另一种编程语言中可能不完全相同。

为使用更符合惯例的 Go,你可以进行几个小修改:

  • 通过使用 += 操作符来将 sum = sum + count 更简洁地表达为 sum += count
  • 通过使用 分配并推断类型运算符 来表达 count := 1 而不是 var count int 跟着 count = 1:= 语法同时定义并初始化 count 变量。
  • count 的声明移到 for 循环的头中。这减少了一些认知负担,也通过减少程序员在任何时候都必须心里记着的变量数目来提高可读性。这个更改还通过在最接近其使用的地方和最小的范围中声明变量来增加安全性,从而减少了在代码不断演进的过程中对变量进行意外操作的可能性。

上述改动的组合将产生以下代码:

package main
import "fmt"

func main() {
  fmt.Println("adding 1 to 10 ..")
  var sum int
  for count := 1; count <= 10; count++ {
    sum += count
  }

  fmt.Printf("The sum is %d\n", sum)
}

你可以使用这个 Go.dev 的 链接 在 Go 试验场中尝试这个示例程序。

C 和 Go 相似但不同

通过在两种编程语言中编写相同的程序,你可以看到 C 和 Go 这两种语言虽然相似但仍然不同。将从 C 转换到 Go 时需要注意以下几点:

  • 在 C 中,每个程序指令都必须以分号结尾。这告诉编译器一个语句在哪里结束,下一个在哪里开始。在 Go 中,分号是有效的,但几乎总是可以推断出来。
  • 虽然大多数现代 C 编译器会为你将变量初始化为零值,但 C 语言规范指出,变量得到的是内存中的任意值。Go 值总是初始化为其零值。这有助于使 Go 成为一种更具内存安全的语言。这种差异在使用指针时变得更加有趣。
  • 注意 Go 程序包对导入标识符的使用方式。例如,fmt 是一个实现格式化输入和输出的函数,类似于 C 中的 stdio.h 中的 printfscanffmt 程序包在 pkg.go.dev/fmt 中有文档描述。
  • 在 Go 中,main 函数总是以退出代码 0 返回。如果你希望返回其他值,你必须调用 os.Exit(n),其中 n 通常为 1 以表示错误。这可以从任何地方调用,不仅仅是 main 函数,来终止程序。你可以在 C 中使用在 stdlib.h 中定义的 exit(n) 函数来实现相同的效果。

(题图:MJ/8f731484-2dc3-4bac-b895-cbc92a63b48b)


via: https://opensource.com/article/23/4/c-vs-go-programming-languages

作者:Jim Hall 选题:lkxed 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出