使用LTSP为Kubernetes构建网络就绪的服务器场


在本文中,我想向您展示一种很酷的技术,我成功地将其用于Kubernetes。 这对于构建大型集群非常有用。


从现在开始,您不再需要考虑为每个节点安装操作系统和单独的软件包。 怎么了 您可以通过Dockerfile自动完成所有这些操作!


您可以购买数百台新服务器,将它们添加到您的工作环境中,并几乎立即将它们准备好使用,这一事实的确令人惊奇!


感兴趣吗? 现在让我们按顺序讨论一切。


总结


首先,我们需要确切了解该电路的工作原理。


简而言之,对于所有节点,我们正在使用OS,Docker,Kubelet和其他所有内容准备单个映像。
CI使用Dockerfile自动将该系统映像与内核一起构建。
终端节点直接通过网络从该映像加载OS和内核。


节点使用overlayfs作为根文件系统,因此,在重新引导的情况下,所有更改都会丢失(以及docker容器)。
有一个主要的配置,您可以在其中描述安装点以及在加载节点时应执行的一些命令(例如,添加ssh键和kubeadm join的命令)


图像准备过程


我们将使用LTSP项目,因为它为我们提供了组织网络引导所需的一切。
通常,LTSP是一堆shell脚本,使我们的生活更加轻松。


它提供了一个initramfs模块,几个帮助程序脚本以及某种配置系统,该系统可以在加载的早期(甚至在调用init之前)为系统做准备。


这是图像准备过程的样子:


  • 在chroot环境中部署基本系统。
  • 我们进行必要的更改,安装软件。
  • 运行ltsp-build-image命令

之后,您将从此chroot获取压缩的映像,其中包含所有安装的软件。
每个节点都将在引导时下载该映像并将其用作rootfs。
要进行更新,只需重新启动节点,新映像将被下载并用于rootfs。


服务器组件


在我们的案例中,LTSP的服务器部分仅包含两个组件:


  • TFTP服务器 -TFTP是初始化协议,用于加载内核,initramfs和主要配置-lts.conf。
  • NBD服务器 -NBD协议用于将压缩的rootfs映像传递给客户端。 这是最快的方法,但是如果需要,可以将其替换为NFS或AoE。

您还需要具备:


  • DHCP服务器 -它将分发IP配置以及我们的客户端所需的其他几个选项,以便它们可以从我们的LTSP服务器启动。

节点加载过程


节点加载过程说明


  • 首先,该节点将为next-server filename请求DHCP IP地址和选项。
  • 然后,该节点将应用设置并下载引导程序(pxelinux或grub)
  • 引导程序将下载并使用内核和initramfs加载配置。
  • 然后,它将使用为内核指定的特定选项加载内核和initramfs。
  • 在启动时,initramfs模块将处理来自cmdline的参数并执行一些操作,例如连接nbd设备,准备覆盖rootfs等。
  • 之后,将调用特殊的ltsp-init,而不是通常的init。
  • ltsp-init脚本将在调用主init之前尽早准备系统。 基本上,这里使用lts.conf(主配置文件)中的选项:这是更新fstab和rc.local等中的记录。
  • 然后将调用主init(systemd),它将照常加载已配置的系统,从fstab挂载共享资源,启动目标和服务,并从rc.local执行命令。
  • 结果,我们得到了一个完整配置并已加载的系统,可以采取进一步的措施。

服务器准备


如我所说,我使用Dockerfile自动为LTSP服务器准备了压缩的映像。 这种方法还不错,因为所有构建步骤都可以在git存储库中描述。 您可以控制版本,使用标签,应用CI以及用于准备常规Docker项目的所有功能。


另一方面,您可以通过手动执行所有步骤来手动部署LTSP服务器,这对于培训目的和理解基本原理很有用。
如果只想在没有Dockerfile的情况下尝试LTSP,请手动运行本文中列出的命令。


使用的补丁列表


目前,LTSP存在一些缺陷,该项目的作者不太愿意接受更正。 幸运的是,LTSP易于定制,因此我为自己准备了一些补丁,我将在此处提供。
如果社区热烈接受我的决定,也许有一天我会成熟起来。


  • Feature-grub.diff
    默认情况下,LTSP不支持EFI,因此我准备了一个补丁,该补丁添加了具有EFI支持的GRUB2。
  • feature_preinit.diff
    此修补程序在lts.conf中添加了PREINIT选项,使您可以在调用主init之前运行任意命令。 这对于修改系统单元和网络设置很有用。 值得注意的是,引导环境中的所有变量都已保存,您可以在通过此选项调用的脚本中使用它们。
  • feature_initramfs_params_from_lts_conf.diff
    使用禁用的NBD_TO_RAM选项解决了该问题,在此修补程序之后,您可以在chroot中的lts.conf中指定它。 (不是tftp目录中的那个)
  • nbd-server-wrapper.sh
    这不是补丁,而只是一个shell脚本,它允许您在前驱中运行nbd-server,如果您想在Docker容器中运行nbd-server,则将需要它。

Dockerfile阶段


我们将在Dockerfile中使用阶段构建来仅保存Docker映像的必要部分,其余未使用的部分将从最终映像中排除。


 ltsp-base (    ltsp ) | |---basesystem | ( chroot-     ) | | | |---builder | | (    ,  ) | | | '---ltsp-image | (  , docker, kubelet   squashed ) | '---final-stage ( squashed ,   initramfs   stage) 

阶段1:以ltsp为基础


好的,让我们开始吧,这是Dockerfile的第一部分:


 FROM ubuntu:16.04 as ltsp-base ADD nbd-server-wrapper.sh /bin/ ADD /patches/feature-grub.diff /patches/feature-grub.diff RUN apt-get -y update \ && apt-get -y install \ ltsp-server \ tftpd-hpa \ nbd-server \ grub-common \ grub-pc-bin \ grub-efi-amd64-bin \ curl \ patch \ && sed -i 's|in_target mount|in_target_nofail mount|' \ /usr/share/debootstrap/functions \ #   EFI   Grub (#1745251) && patch -p2 -d /usr/sbin < /patches/feature-grub.diff \ && rm -rf /var/lib/apt/lists \ && apt-get clean 

目前,我们的docker映像已经安装了以下内容:


  • NBD服务器
  • TFTP服务器
  • 具有grub引导加载程序支持的LTSP脚本(用于EFI)

阶段2:基本系统


在这一阶段,我们将使用基本系统准备chroot环境,并使用内核安装主要软件。
我们将使用通常的debootstrap而不是ltsp-build-client来准备映像,因为ltsp-build-client将安装GUI和一些其他不必要的东西,这些显然对部署服务器没有用。


 FROM ltsp-base as basesystem ARG DEBIAN_FRONTEND=noninteractive #    RUN mkdir -p /opt/ltsp/amd64/proc/self/fd \ && touch /opt/ltsp/amd64/proc/self/fd/3 \ && debootstrap --arch amd64 xenial /opt/ltsp/amd64 \ && rm -rf /opt/ltsp/amd64/proc/* #   RUN echo "\ deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse\n\ deb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse\n\ deb http://archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse" \ > /opt/ltsp/amd64/etc/apt/sources.list \ && ltsp-chroot apt-get -y update \ && ltsp-chroot apt-get -y upgrade #   LTSP RUN ltsp-chroot apt-get -y install ltsp-client-core #   initramfs # 1:    /etc/lts.conf    (#1680490) # 2:   PREINIT   lts.conf ADD /patches /patches RUN patch -p4 -d /opt/ltsp/amd64/usr/share < /patches/feature_initramfs_params_from_lts_conf.diff \ && patch -p3 -d /opt/ltsp/amd64/usr/share < /patches/feature_preinit.diff #  LTSP_NBD_TO_RAM    ,     ram: RUN echo "[Default]\nLTSP_NBD_TO_RAM = true" \ > /opt/ltsp/amd64/etc/lts.conf #   RUN echo 'APT::Install-Recommends "0";\nAPT::Install-Suggests "0";' \ >> /opt/ltsp/amd64/etc/apt/apt.conf.d/01norecommend \ && ltsp-chroot apt-get -y install \ software-properties-common \ apt-transport-https \ ca-certificates \ ssh \ bridge-utils \ pv \ jq \ vlan \ bash-completion \ screen \ vim \ mc \ lm-sensors \ htop \ jnettop \ rsync \ curl \ wget \ tcpdump \ arping \ apparmor-utils \ nfs-common \ telnet \ sysstat \ ipvsadm \ ipset \ make #   RUN ltsp-chroot apt-get -y install linux-generic-hwe-16.04 

请注意,某些软件包(例如lvm2)可能会遇到问题。 它们尚未完全优化,无法安装在无特权的chroot中。 他们的安装后脚本尝试调用特权命令,这些命令可能会失败并阻止整个软件包的安装。


解决方案:


  • 如果在安装内核之前先安装它们,则可以成功安装其中的一些(例如,lvm2)
  • 但是对于其中一些,您将需要使用此替代方法来安装,而无需安装后脚本。

第三阶段:建造者


在这个阶段,我们可以从源头收集所有必要的软件和内核模块,这是很酷的事情,它可以在这个阶段以全自动模式进行。
如果您不需要从艺术家那里收集任何东西,请跳过此步骤。


我将举一个安装最新版本的MLNX_EN驱动程序的示例:


 FROM basesystem as builder #  cpuinfo (   ) RUN cp /proc/cpuinfo /opt/ltsp/amd64/proc/cpuinfo #    Mellanox driver RUN ltsp-chroot sh -cx \ ' VERSION=4.3-1.0.1.0-ubuntu16.04-x86_64 \ && curl -L http://www.mellanox.com/downloads/ofed/MLNX_EN-${VERSION%%-ubuntu*}/mlnx-en-${VERSION}.tgz \ | tar xzf - \ && export \ DRIVER_DIR="$(ls -1 | grep "MLNX_OFED_LINUX-\|mlnx-en-")" \ KERNEL="$(ls -1t /lib/modules/ | head -n1)" \ && cd "$DRIVER_DIR" \ && ./*install --kernel "$KERNEL" --without-dkms --add-kernel-support \ && cd - \ && rm -rf "$DRIVER_DIR" /tmp/mlnx-en* /tmp/ofed*' #    RUN ltsp-chroot sh -c \ ' export KERNEL="$(ls -1t /usr/src/ | grep -m1 "^linux-headers" | sed "s/^linux-headers-//g")" \ && tar cpzf /modules.tar.gz /lib/modules/${KERNEL}/updates' 

阶段4:ltsp-image


在这一阶段,我们将确定上一步收集的内容:


 FROM basesystem as ltsp-image #    COPY --from=builder /opt/ltsp/amd64/modules.tar.gz /opt/ltsp/amd64/modules.tar.gz #    RUN ltsp-chroot sh -c \ ' export KERNEL="$(ls -1t /usr/src/ | grep -m1 "^linux-headers" | sed "s/^linux-headers-//g")" \ && tar xpzf /modules.tar.gz \ && depmod -a "${KERNEL}" \ && rm -f /modules.tar.gz' 

现在,我们将进行其他更改以完成LTSP映像:


 #  docker RUN ltsp-chroot sh -c \ ' curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \ && echo "deb https://download.docker.com/linux/ubuntu xenial stable" \ > /etc/apt/sources.list.d/docker.list \ && apt-get -y update \ && apt-get -y install \ docker-ce=$(apt-cache madison docker-ce | grep 18.06 | head -1 | awk "{print $ 3}")' #    docker RUN DOCKER_OPTS="$(echo \ --storage-driver=overlay2 \ --iptables=false \ --ip-masq=false \ --log-driver=json-file \ --log-opt=max-size=10m \ --log-opt=max-file=5 \ )" \ && sed "/^ExecStart=/ s|$| $DOCKER_OPTS|g" \ /opt/ltsp/amd64/lib/systemd/system/docker.service \ > /opt/ltsp/amd64/etc/systemd/system/docker.service #  kubeadm, kubelet  kubectl RUN ltsp-chroot sh -c \ ' curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \ && echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" \ > /etc/apt/sources.list.d/kubernetes.list \ && apt-get -y update \ && apt-get -y install kubelet kubeadm kubectl cri-tools' #    RUN rm -f /opt/ltsp/amd64/etc/apt/apt.conf.d/20auto-upgrades #   apparmor RUN ltsp-chroot find /etc/apparmor.d \ -maxdepth 1 \ -type f \ -name "sbin.*" \ -o -name "usr.*" \ -exec ln -sf "{}" /etc/apparmor.d/disable/ \; #    (cmdline) RUN KERNEL_OPTIONS="$(echo \ init=/sbin/init-ltsp \ forcepae \ console=tty1 \ console=ttyS0,9600n8 \ nvme_core.default_ps_max_latency_us=0 \ )" \ && sed -i "/^CMDLINE_LINUX_DEFAULT=/ s|=.*|=\"${KERNEL_OPTIONS}\"|" \ "/opt/ltsp/amd64/etc/ltsp/update-kernels.conf" 

现在,从我们的chroot制作一个压缩图像:


 #   RUN rm -rf /opt/ltsp/amd64/var/lib/apt/lists \ && ltsp-chroot apt-get clean #  squashed  RUN ltsp-update-image 

阶段5:最后阶段


在最后阶段,我们仅使用initramfs保存压缩的图像和内核


 FROM ltsp-base COPY --from=ltsp-image /opt/ltsp/images /opt/ltsp/images COPY --from=ltsp-image /etc/nbd-server/conf.d /etc/nbd-server/conf.d COPY --from=ltsp-image /var/lib/tftpboot /var/lib/tftpboot 

好的,现在我们有了一个docker映像,其中包括:


  • TFTP服务器
  • NBD服务器
  • 配置的引导程序
  • initramfs的内核
  • 压缩的rootfs图像

使用方法


好的,现在我们的带有LTSP服务器,内核,initramfs和压缩后的rootfs的Docker映像已完全准备就绪,我们可以使用它运行部署。


我们可以照常做,但是还有另一个问题需要解决。
不幸的是,我们无法在部署中使用常规的Kubernetes服务,因为在启动时节点不是Kubernetes集群的一部分,它们需要使用externalIP,但是Kubernetes始终将NAT用于externalIP,并且目前无法更改此行为。


我知道两种避免这种情况的方法:使用hostNetwork: true或使用pipework ,第二个选项还将为我们提供容错能力,因为 如果发生故障,该IP地址将与容器一起移至另一个节点。 不幸的是,管道工程不是一种本机且不太安全的方法。
如果您知道任何更合适的解决方案,请告诉我们。


这是使用hostNetwork进行部署的示例:


 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: ltsp-server labels: app: ltsp-server spec: selector: matchLabels: name: ltsp-server replicas: 1 template: metadata: labels: name: ltsp-server spec: hostNetwork: true containers: - name: tftpd image: registry.example.org/example/ltsp:latest command: [ "/usr/sbin/in.tftpd", "-L", "-u", "tftp", "-a", ":69", "-s", "/var/lib/tftpboot" ] lifecycle: postStart: exec: command: ["/bin/sh", "-c", "cd /var/lib/tftpboot/ltsp/amd64; ln -sf config/lts.conf ." ] volumeMounts: - name: config mountPath: "/var/lib/tftpboot/ltsp/amd64/config" - name: nbd-server image: registry.example.org/example/ltsp:latest command: [ "/bin/nbd-server-wrapper.sh" ] volumes: - name: config configMap: name: ltsp-config 

您可能已经注意到,这里还使用了带有lts.conf文件的configmap。
例如,我将给出部分配置:


 apiVersion: v1 kind: ConfigMap metadata: name: ltsp-config data: lts.conf: | [default] KEEP_SYSTEM_SERVICES = "ssh ureadahead dbus-org.freedesktop.login1 systemd-logind polkitd cgmanager ufw rpcbind nfs-kernel-server" PREINIT_00_TIME = "ln -sf /usr/share/zoneinfo/Europe/Prague /etc/localtime" PREINIT_01_FIX_HOSTNAME = "sed -i '/^127.0.0.2/d' /etc/hosts" PREINIT_02_DOCKER_OPTIONS = "sed -i 's|^ExecStart=.*|ExecStart=/usr/bin/dockerd -H fd:// --storage-driver overlay2 --iptables=false --ip-masq=false --log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5|' /etc/systemd/system/docker.service" FSTAB_01_SSH = "/dev/data/ssh /etc/ssh ext4 nofail,noatime,nodiratime 0 0" FSTAB_02_JOURNALD = "/dev/data/journal /var/log/journal ext4 nofail,noatime,nodiratime 0 0" FSTAB_03_DOCKER = "/dev/data/docker /var/lib/docker ext4 nofail,noatime,nodiratime 0 0" # Each command will stop script execution when fail RCFILE_01_SSH_SERVER = "cp /rofs/etc/ssh/*_config /etc/ssh; ssh-keygen -A" RCFILE_02_SSH_CLIENT = "mkdir -p /root/.ssh/; echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBSLYRaORL2znr1V4a3rjDn3HDHn2CsvUNK1nv8+CctoICtJOPXl6zQycI9KXNhANfJpc6iQG1ZPZUR74IiNhNIKvOpnNRPyLZ5opm01MVIDIZgi9g0DUks1g5gLV5LKzED8xYKMBmAfXMxh/nsP9KEvxGvTJB3OD+/bBxpliTl5xY3Eu41+VmZqVOz3Yl98+X8cZTgqx2dmsHUk7VKN9OZuCjIZL9MtJCZyOSRbjuo4HFEssotR1mvANyz+BUXkjqv2pEa0I2vGQPk1VDul5TpzGaN3nOfu83URZLJgCrX+8whS1fzMepUYrbEuIWq95esjn0gR6G4J7qlxyguAb9 admin@kubernetes' >> /root/.ssh/authorized_keys" RCFILE_03_KERNEL_DEBUG = "sysctl -w kernel.unknown_nmi_panic=1 kernel.softlockup_panic=1; modprobe netconsole netconsole=@/vmbr0,@10.9.0.15/" RCFILE_04_SYSCTL = "sysctl -w fs.file-max=20000000 fs.nr_open=20000000 net.ipv4.neigh.default.gc_thresh1=80000 net.ipv4.neigh.default.gc_thresh2=90000 net.ipv4.neigh.default.gc_thresh3=100000" RCFILE_05_FORWARD = "echo 1 > /proc/sys/net/ipv4/ip_forward" RCFILE_06_MODULES = "modprobe br_netfilter" RCFILE_07_JOIN_K8S = "kubeadm join --token 2a4576.504356e45fa3d365 10.9.0.20:6443 --discovery-token-ca-cert-hash sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 'SSH-RSA AAAAB3NzaC1yc2EAAAADAQABAAABAQDBSLYRaORL2znr1V4a3rjDn3HDHn2CsvUNK1nv8 + CctoICtJOPXl6zQycI9KXNhANfJpc6iQG1ZPZUR74IiNhNIKvOpnNRPyLZ5opm01MVIDIZgi9g0DUks1g5gLV5LKzED8xYKMBmAfXMxh / nsP9KEvxGvTJB3OD + / + bBxpliTl5xY3Eu41 + VmZqVOz3Yl98 + X8cZTgqx2dmsHUk7VKN9OZuCjIZL9MtJCZyOSRbjuo4HFEssotR1mvANyz + BUXkjqv2pEa0I2vGQPk1VDul5TpzGaN3nOfu83URZLJgCrX管理员8whS1fzMepUYrbEuIWq95esjn0gR6G4J7qlxyguAb9 @ kubernetes' >> /root/.ssh/authorized_keys” apiVersion: v1 kind: ConfigMap metadata: name: ltsp-config data: lts.conf: | [default] KEEP_SYSTEM_SERVICES = "ssh ureadahead dbus-org.freedesktop.login1 systemd-logind polkitd cgmanager ufw rpcbind nfs-kernel-server" PREINIT_00_TIME = "ln -sf /usr/share/zoneinfo/Europe/Prague /etc/localtime" PREINIT_01_FIX_HOSTNAME = "sed -i '/^127.0.0.2/d' /etc/hosts" PREINIT_02_DOCKER_OPTIONS = "sed -i 's|^ExecStart=.*|ExecStart=/usr/bin/dockerd -H fd:// --storage-driver overlay2 --iptables=false --ip-masq=false --log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5|' /etc/systemd/system/docker.service" FSTAB_01_SSH = "/dev/data/ssh /etc/ssh ext4 nofail,noatime,nodiratime 0 0" FSTAB_02_JOURNALD = "/dev/data/journal /var/log/journal ext4 nofail,noatime,nodiratime 0 0" FSTAB_03_DOCKER = "/dev/data/docker /var/lib/docker ext4 nofail,noatime,nodiratime 0 0" # Each command will stop script execution when fail RCFILE_01_SSH_SERVER = "cp /rofs/etc/ssh/*_config /etc/ssh; ssh-keygen -A" RCFILE_02_SSH_CLIENT = "mkdir -p /root/.ssh/; echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBSLYRaORL2znr1V4a3rjDn3HDHn2CsvUNK1nv8+CctoICtJOPXl6zQycI9KXNhANfJpc6iQG1ZPZUR74IiNhNIKvOpnNRPyLZ5opm01MVIDIZgi9g0DUks1g5gLV5LKzED8xYKMBmAfXMxh/nsP9KEvxGvTJB3OD+/bBxpliTl5xY3Eu41+VmZqVOz3Yl98+X8cZTgqx2dmsHUk7VKN9OZuCjIZL9MtJCZyOSRbjuo4HFEssotR1mvANyz+BUXkjqv2pEa0I2vGQPk1VDul5TpzGaN3nOfu83URZLJgCrX+8whS1fzMepUYrbEuIWq95esjn0gR6G4J7qlxyguAb9 admin@kubernetes' >> /root/.ssh/authorized_keys" RCFILE_03_KERNEL_DEBUG = "sysctl -w kernel.unknown_nmi_panic=1 kernel.softlockup_panic=1; modprobe netconsole netconsole=@/vmbr0,@10.9.0.15/" RCFILE_04_SYSCTL = "sysctl -w fs.file-max=20000000 fs.nr_open=20000000 net.ipv4.neigh.default.gc_thresh1=80000 net.ipv4.neigh.default.gc_thresh2=90000 net.ipv4.neigh.default.gc_thresh3=100000" RCFILE_05_FORWARD = "echo 1 > /proc/sys/net/ipv4/ip_forward" RCFILE_06_MODULES = "modprobe br_netfilter" RCFILE_07_JOIN_K8S = "kubeadm join --token 2a4576.504356e45fa3d365 10.9.0.20:6443 --discovery-token-ca-cert-hash sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 

  • KEEP_SYSTEM_SERVICES-引导LTSP期间会自动删除某些服务,需要此变量以防止此处列出的服务出现此行为。
  • PREINIT_ * -将在运行systemd之前执行此处列出的命令(此功能由feature_preinit.diff补丁添加)
  • FSTAB_ * -此处列出的行将添加到/etc/fstab文件中。
    您可能会注意到,我正在使用nofail选项,它具有以下行为:如果该部分不存在,则下载将继续而不会出现错误。
  • RCFILE_ * -这些命令将添加到rc.local文件,该文件将在引导时由systemd调用。
    在这里,我加载必要的内核模块,运行一些sysctl设置,然后运行kubeadm join命令,该命令将节点添加到kubernetes集群中。

您可以从lts.conf手册页中获取有关所有变量的更多详细信息。


现在,您可以配置DHCP。 本质上,您需要指定next-serverfilename选项。


我使用的是ISC-DHCP服务器,下面以dhcpd.conf为例:


 shared-network ltsp-netowrk { subnet 10.9.0.0 netmask 255.255.0.0 { authoritative; default-lease-time -1; max-lease-time -1; option domain-name "example.org"; option domain-name-servers 10.9.0.1; option routers 10.9.0.1; next-server ltsp-1; # write ltsp-server hostname here if option architecture = 00:07 { filename "/ltsp/amd64/grub/x86_64-efi/core.efi"; } else { filename "/ltsp/amd64/grub/i386-pc/core.0"; } range 10.9.200.0 10.9.250.254; } 

您可以从这里开始,但是就我而言,我有数台LTSP服务器,并且使用Ansible剧本为每个节点配置了单独的静态IP地址和必要的选项。


尝试启动第一个节点,如果一切都正确完成,则将在该节点上加载一个系统。 该节点也将添加到Kubernetes集群中。


现在,您可以尝试进行自己的更改。


如果您还需要其他东西,请注意,可以很容易地定制LTSP以满足您的需求。 随时查看源代码,您可以在其中找到很多答案。


加入我们的电报频道: @ltsp_ru

Source: https://habr.com/ru/post/zh-CN423785/


All Articles