本文发表已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已不正确。

使用 Kubeadm 引导离线集群

有没有想过软件是如何部署到故意与互联网和其他网络断开连接的系统上的?这些系统通常由于其敏感性而被断开连接。敏感如公用事业(电力/水)、银行、医疗保健、武器系统、其他政府用例等。如果您的 Kubernetes 在水下航行器上运行,有时它在技术上是一个水隙。尽管如此,这些环境仍然需要软件才能运行。这种在断开连接的状态下部署的概念就是部署到气隙的另一侧的含义。

同样,尽管有这种姿态,软件仍然需要在这些环境中运行。传统上,软件工件是通过硬盘驱动器、U盘、CD 或软盘(对于旧系统,仍然会发生这种情况)在气隙上物理传输的。Kubernetes 特别适合在气隙后运行软件,原因有很多,主要是由于其声明性性质。

在这篇博客文章中,我将逐步介绍在气隙实验室环境中使用 Fedora Linux 和 kubeadm 引导 Kubernetes 集群的过程。

气隙虚拟机设置

建立一个真正的气隙网络可能需要一些工作,因此对于这篇文章,我将使用笔记本电脑上的一个示例虚拟机并进行一些网络修改。以下是拓扑结构

Topology on the host/laptop which shows that connectivity to the internet from the air gap VM is not possible. However, connectivity between the host/laptop and the VM is possible

本地拓扑

此虚拟机的网络连接将被禁用,但不会关闭虚拟机的虚拟网卡。相反,它的网络将通过将默认路由注入虚拟接口来关闭,从而使任何互联网托管的内容都无法访问。但是,虚拟机仍然有一条到主机桥接接口的连接路由,这意味着到主机的网络连接仍然有效。这种姿态意味着数据可以通过 scp 从主机/笔记本电脑传输到虚拟机,即使虚拟机上的默认路由阻止了所有不是发往本地桥接子网的流量。这种类型的传输类似于在气隙上传输数据,并且将在整篇文章中使用。

关于实验室设置的其他详细信息

虚拟机操作系统: Fedora 37
Kubernetes 版本: v1.27.3
CNI 插件版本: v1.3.0
CNI 提供程序和版本: Flannel v0.22.0

虽然这个单虚拟机实验室是一个简化的示例,但下图更近似地展示了真实的气隙环境可能的样子

Example production topology which shows 3 control plane Kubernetes nodes and 'n' worker nodes along with a Docker registry in an air-gapped environment.  Additionally shows two workstations, one on each side of the air gap and an IT admin which physically carries the artifacts across.

请注意,环境和互联网之间仍然存在有意的隔离。为了使图表简单,还省略了一些内容,例如在气隙安全侧的恶意软件扫描。

回到单虚拟机实验室环境。

识别所需的软件工件

我已费尽周折地确定了所有需要在气隙上传输的必要软件组件,以便启动此集群

  • Docker(用于托管内部容器镜像注册表)
  • Containerd
  • libcgroup
  • socat
  • conntrack-tools
  • CNI 插件
  • crictl
  • kubeadm
  • kubelet
  • kubectl 和 k9s(严格来说,这些不是引导集群所必需的,但它们有助于与集群交互)
  • kubelet.service systemd 文件
  • kubeadm 配置文件
  • Docker 注册表容器镜像
  • Kubernetes 组件容器镜像
  • CNI 网络插件容器镜像(此实验室将使用Flannel
  • CNI 网络插件清单
  • CNI 工具容器镜像

我识别这些的方式是尝试进行安装,并解决所有因需要额外依赖项而抛出的错误。在真正的气隙场景中,每次跨气隙传输工件可能需要安装人员花费 20 分钟到几周的时间。也就是说,目标系统可能位于与您的办公桌在同一楼层的数据中心、位于偏远地区的卫星下行链路设施或在海上的潜艇上。了解该系统在任何给定时间的状态非常重要,这样您就知道必须带什么。

为 K8s 准备节点

在下载并将工件移动到虚拟机之前,让我们先准备好该虚拟机以运行 Kubernetes。

虚拟机准备

以普通用户身份运行这些步骤

为软件工件创建目标目录

mkdir ~/tmp

以超级用户(root)身份运行以下步骤

写入 /etc/sysctl.d/99-k8s-cri.conf

cat > /etc/sysctl.d/99-k8s-cri.conf << EOF
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables=1
EOF

写入 /etc/modules-load.d/k8s.conf(启用 overlaynbr_netfilter

echo -e overlay\\nbr_netfilter > /etc/modules-load.d/k8s.conf

安装 iptables

dnf -y install iptables-legacy

将 iptables 设置为使用旧版模式(而不是模拟 iptablesnft

update-alternatives --set iptables /usr/sbin/iptables-legacy

关闭交换

touch /etc/systemd/zram-generator.conf
systemctl mask [email protected]
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

禁用 firewalld(这在演示环境中是允许的)

systemctl disable --now firewalld

禁用 systemd-resolved

systemctl disable --now systemd-resolved

配置 NetworkManager 的 DNS 默认值

sed -i '/\[main\]/a dns=default' /etc/NetworkManager/NetworkManager.conf

清除系统级 DNS 解析器配置

unlink /etc/resolv.conf || true
touch /etc/resolv.conf

禁用 SELinux (仅用于演示 - 在生产环境中执行此操作前请检查!)

setenforce 0

确保所有更改在重新启动后仍然存在

reboot

下载所有工件

在笔记本电脑/主机上,下载上一节中列出的所有工件。由于气隙虚拟机运行 Fedora 37,因此此部分中显示的所有依赖项都适用于 Fedora 37。请注意,此过程仅适用于 AArch64 或 AMD64 CPU 架构,因为它们是最流行和最广泛可用的架构。您可以在您具有写入权限的任何位置执行此过程;您的主目录是一个非常合适的选择。

请注意,现在可以在 pkgs.k8s.io 上找到需要跨越传输的 Kubernetes 工件的操作系统软件包。此博客文章将结合使用 Fedora 存储库和 GitHub 来下载所有必需的工件。当您在自己的集群上执行此操作时,您应该决定是使用官方 Kubernetes 软件包,还是使用操作系统发行版的官方软件包 - 这两者都是有效的选择。

# Set architecture variables
UARCH=$(uname -m)

if [["$UARCH" == "arm64" || "$UARCH" == "aarch64"]]; then

    ARCH="aarch64"
    K8s_ARCH="arm64"

else

    ARCH="x86_64"
    K8s_ARCH="amd64"

fi

设置要使用的软件版本的环境变量

CNI_PLUGINS_VERSION="v1.3.0"
CRICTL_VERSION="v1.27.0"
KUBE_RELEASE="v1.27.3"
RELEASE_VERSION="v0.15.1"
K9S_VERSION="v0.27.4"

创建一个 download 目录,更改到其中,并下载所有 RPM 和配置文件

mkdir download && cd download

curl -O https://download.docker.com/linux/fedora/37/${ARCH}/stable/Packages/docker-ce-cli-23.0.2-1.fc37.${ARCH}.rpm

curl -O https://download.docker.com/linux/fedora/37/${ARCH}/stable/Packages/containerd.io-1.6.19-3.1.fc37.${ARCH}.rpm

curl -O https://download.docker.com/linux/fedora/37/${ARCH}/stable/Packages/docker-compose-plugin-2.17.2-1.fc37.${ARCH}.rpm

curl -O https://download.docker.com/linux/fedora/37/${ARCH}/stable/Packages/docker-ce-rootless-extras-23.0.2-1.fc37.${ARCH}.rpm

curl -O https://download.docker.com/linux/fedora/37/${ARCH}/stable/Packages/docker-ce-23.0.2-1.fc37.${ARCH}.rpm

curl -O https://download-ib01.fedoraproject.org/pub/fedora/linux/releases/37/Everything/${ARCH}/os/Packages/l/libcgroup-3.0-1.fc37.${ARCH}.rpm

echo -e "\nDownload Kubernetes Binaries"

curl -L -O "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${K8s_ARCH}-${CNI_PLUGINS_VERSION}.tgz"

curl -L -O "https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-${K8s_ARCH}.tar.gz"

curl -L --remote-name-all https://dl.k8s.io/release/${KUBE_RELEASE}/bin/linux/${K8s_ARCH}/{kubeadm,kubelet}

curl -L -O "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubelet/lib/systemd/system/kubelet.service"

curl -L -O "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf"

curl -L -O "https://dl.k8s.io/release/${KUBE_RELEASE}/bin/linux/${K8s_ARCH}/kubectl"

echo -e "\nDownload dependencies"

curl -O "https://dl.fedoraproject.org/pub/fedora/linux/releases/37/Everything/${ARCH}/os/Packages/s/socat-1.7.4.2-3.fc37.${ARCH}.rpm"

curl -O "https://dl.fedoraproject.org/pub/fedora/linux/releases/37/Everything/${ARCH}/os/Packages/l/libcgroup-3.0-1.fc37.${ARCH}.rpm"

curl -O "https://dl.fedoraproject.org/pub/fedora/linux/releases/37/Everything/${ARCH}/os/Packages/c/conntrack-tools-1.4.6-4.fc37.${ARCH}.rpm"

curl -LO "https://github.com/derailed/k9s/releases/download/${K9S_VERSION}/k9s_Linux_${K8s_ARCH}.tar.gz"

curl -LO "https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml"

下载所有必要的容器镜像

images=(
    "registry.k8s.io/kube-apiserver:${KUBE_RELEASE}"
    "registry.k8s.io/kube-controller-manager:${KUBE_RELEASE}"
    "registry.k8s.io/kube-scheduler:${KUBE_RELEASE}"
    "registry.k8s.io/kube-proxy:${KUBE_RELEASE}"
    "registry.k8s.io/pause:3.9"
    "registry.k8s.io/etcd:3.5.7-0"
    "registry.k8s.io/coredns/coredns:v1.10.1"
    "registry:2.8.2"
    "flannel/flannel:v0.22.0"
    "flannel/flannel-cni-plugin:v1.1.2"
)

for image in "${images[@]}"; do
    # Pull the image from the registry
    docker pull "$image"

    # Save the image to a tar file on the local disk
    image_name=$(echo "$image" | sed 's|/|_|g' | sed 's/:/_/g')
    docker save -o "${image_name}.tar" "$image"

done

上面的命令将查看当前主机/笔记本电脑的 CPU 架构,创建并更改到名为 download 的目录,最后下载所有依赖项。然后,必须通过 scp 将每个文件传输到气隙。命令的确切语法将因虚拟机上的用户、您是否创建了 SSH 密钥以及气隙虚拟机的 IP 而异。大致语法为

scp -i <<SSH_KEY>> <<FILE>> <<AIRGAP_VM_USER>>@<<AIRGAP_VM_IP>>:~/tmp/

将所有文件传输到气隙虚拟机后,博客文章的其余部分将在虚拟机中进行。打开该系统的终端会话。

将工件放到适当的位置

现在,引导 Kubernetes 集群所需的一切都存在于气隙虚拟机上。本节要复杂得多,因为各种类型的工件现在都在气隙虚拟机上的磁盘上。在气隙虚拟机上获取 root shell,因为本节的其余部分将从那里执行。让我们首先设置与主机/笔记本电脑上设置的相同的架构变量和环境,然后安装所有 RPM 软件包

UARCH=$(uname -m)
# Set architecture variables

if [["$UARCH" == "arm64" || "$UARCH" == "aarch64"]]; then

    ARCH="aarch64"
    K8s_ARCH="arm64"

else

    ARCH="x86_64"
    K8s_ARCH="amd64"

fi

# Set environment variables
CNI_PLUGINS_VERSION="v1.3.0"
CRICTL_VERSION="v1.27.0"
KUBE_RELEASE="v1.27.3"
RELEASE_VERSION="v0.15.1"
K9S_VERSION="v0.27.4"

cd ~/tmp/

dnf -y install ./*.rpm

接下来,安装 CNI 插件和 crictl

mkdir -p /opt/cni/bin
tar -C /opt/cni/bin -xz -f "cni-plugins-linux-${K8s_ARCH}-v1.3.0.tgz"
tar -C /usr/local/bin-xz -f "crictl-v1.27.0-linux-${K8s_ARCH}.tar.gz"

使 kubeadm、kubelet 和 kubectl 可执行,并将它们从 /tmp 目录移动到 /usr/local/bin

chmod +x kubeadm kubelet kubectl
mv kubeadm kubelet kubectl /usr/local/bin

为 systemd kubelet 服务文件定义一个覆盖,并将其移动到正确的位置

mkdir -p /etc/systemd/system/kubelet.service.d

sed "s:/usr/bin:/usr/local/bin:g" 10-kubeadm.conf > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

默认情况下禁用 containerd 的 CRI 插件;启用它

sed -i 's/^disabled_plugins = \["cri"\]/#&/' /etc/containerd/config.toml

将自定义的 /etc/docker/daemon.json 文件放到适当的位置

echo '{

"exec-opts": ["native.cgroupdriver=systemd"],

"insecure-registries" : ["localhost:5000"],

"allow-nondistributable-artifacts": ["localhost:5000"],

"log-driver": "json-file",

"log-opts": {

"max-size": "100m"

},

"group": "rnd",

"storage-driver": "overlay2",

"storage-opts": [

"overlay2.override_kernel_check=true"

]

}' > /etc/docker/daemon.json

Docker daemon.json 配置文件中需要强调的两个重要项目。不安全注册表行意味着括号中的注册表不支持 TLS。即使在气隙环境中,这也不是一个好的做法,但对于本实验来说是可以的。allow-nondistributable-artifacts 行告诉 Docker 允许将不可分发的工件推送到此注册表。默认情况下,Docker 不会推送这些层,以避免围绕许可或分发权的潜在问题。Windows 基本容器镜像就是一个很好的例子。此行将允许 Docker 标记为“外部”的层被推送到注册表。虽然对于本文来说不是什么大问题,但某些气隙环境可能需要该行。所有层都必须本地存在,因为气隙环境中的任何东西都无法访问公共容器镜像注册表以获取所需内容。

(重新)启动 Docker 并启用它,以便它在系统启动时启动

systemctl restart docker
systemctl enable docker

启动并启用 containerd 和 kubelet

systemctl enable --now containerd
systemctl enable --now kubelet

在 Docker 中运行的容器镜像仓库仅用于任何 CNI 相关容器和后续的工作负载容器。此仓库用于存放 Kubernetes 组件容器。请注意,nerdctl 也可以作为 Docker 的替代方案,并允许直接与 containerd 交互。选择 Docker 是因为它比较熟悉。

在 Docker 内部启动容器镜像仓库

docker load -i registry_2.8.2.tar
docker run -d -p 5000:5000 --restart=always --name registry registry:2.8.2

将 Flannel 容器加载到 Docker 仓库中

注意选择 Flannel 用于本实验是因为它比较熟悉。请选择最适合您环境的 CNI。

docker load -i flannel_flannel_v0.22.0.tar
docker load -i flannel_flannel-cni-plugin_v1.1.2.tar
docker tag flannel/flannel:v0.22.0 localhost:5000/flannel/flannel:v0.22.0
docker tag flannel/flannel-cni-plugin:v1.1.1 localhost:5000/flannel/flannel-cni-plugin:v1.1.1
docker push localhost:5000/flannel/flannel:v0.22.0
docker push localhost:5000/flannel/flannel-cni-plugin:v1.1.1

通过 ctr 加载 Kubernetes 组件的容器镜像

images_files=(
    "registry.k8s.io/kube-apiserver:${KUBE_RELEASE}"
    "registry.k8s.io/kube-controller-manager:${KUBE_RELEASE}"
    "registry.k8s.io/kube-scheduler:${KUBE_RELEASE}"
    "registry.k8s.io/kube-proxy:${KUBE_RELEASE}"
    "registry.k8s.io/pause:3.9"
    "registry.k8s.io/etcd:3.5.7-0"
    "registry.k8s.io/coredns/coredns:v1.10.1"
    
)


for index in "${!image_files[@]}"; do

    if [[-f "${image_files[$index]}" ]]; then

        # The below line loads the images where they need to be on the VM
        ctr -n k8s.io images import ${image_files[$index]}

    else

        echo "File ${image_files[$index]} not found!" 1>&2

    fi

done

这里一个完全合理的问题可能是:“为什么不使用刚刚建立的 Docker 仓库来存放 Kubernetes 组件镜像?” 即使对传递给 kubeadm 的配置文件进行了适当的修改,这仍然无法实现。

启动 Kubernetes 集群

检查集群是否已在运行,如果已在运行则将其关闭

if systemctl is-active --quiet kubelet; then

    # Reset the Kubernetes cluster

    echo "A Kubernetes cluster is already running. Resetting the cluster..."

    kubeadm reset -f

fi

从隔离的 VM 内部登录到 Docker 仓库

# OK for a demo; use secure credentials in production!

DOCKER_USER=user
DOCKER_PASS=pass
echo ${DOCKER_PASS} | docker login --username=${DOCKER_USER} --password-stdin localhost:5000

创建集群配置文件并初始化集群

echo "---

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
clusterName: kubernetes
kubernetesVersion: v1.27.3
networking:
    dnsDomain: cluster.local
    podSubnet: 10.244.0.0/16 # --pod-network-cidr
    serviceSubnet: 10.96.0.0/12
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
    advertiseAddress: 10.10.10.10 # Update to the IP address of the air gap VM
    bindPort: 6443
nodeRegistration:
    criSocket: unix:///run/containerd/containerd.sock # or rely on autodetection
    name: airgap # this must match the hostname of the air gap VM
# Since this is a single node cluster, this taint has to be commented out,
# otherwise the coredns pods will not come up.
# taints:
# - effect: NoSchedule
# key: node-role.kubernetes.io/master" > kubeadm_cluster.yaml

kubeadm init --config kubeadm_config.yaml

设置 $KUBECONFIG 并使用 kubectl 等待 API 服务器变为健康状态

export KUBECONFIG=/etc/kubernetes/admin.conf

until kubectl get nodes; do
    echo -e "\nWaiting for API server to respond..." 1>&2
    sleep 5

done

设置网络

更新 Flannel 清单中的 Flannel 镜像位置,并应用它

sed -i 's/image: docker\.io/image: localhost:5000/g' kube-flannel.yaml
kubectl apply -f kube-flannel.yaml

运行 kubectl get pods -A --watch 直到所有 Pod 都启动并运行。

运行一个示例 Pod

在集群运行后,下一步是部署工作负载。对于这个简单的演示,将部署 Podinfo 应用程序。

安装 Helm

此过程的第一部分必须从主机/笔记本电脑执行。如果尚未安装,请按照安装 Helm的说明进行安装。

接下来,下载 Linux 的 Helm 二进制文件

UARCH=$(uname -m)
# Reset the architecture variables if needed
if [["$UARCH" == "arm64" || "$UARCH" == "aarch64"]]; then

    ARCH="aarch64"
    K8s_ARCH="arm64"

else

    ARCH="x86_64"
    K8s_ARCH="amd64"

fi

curl -LO https://get.helm.sh/helm-v3.12.2-linux-${K8s_ARCH}.tar.gz

添加 Podinfo Helm 仓库,下载 Podinfo Helm 图表,下载 Podinfo 容器镜像,最后将其保存到本地磁盘

helm repo add https://stefanprodan.github.io/podinfo
helm fetch podinfo/podinfo --version 6.4.0
docker pull ghcr.io/stefanprodan/podinfo:6.4.0

将 podinfo 镜像保存到本地磁盘上的 tar 文件

docker save -o podinfo_podinfo-6.4.0.tar ghcr.io/stefanprodan/podinfo

### Transfer the image across the air gap

Reuse the `~/tmp` directory created on the air gapped VM to transport these artifacts across the air gap:

```bash
scp -i <<SSH_KEY>> <<FILE>> <<AIRGAP_VM_USER>>@<<AIRGAP_VM_IP>>:~/tmp/

在隔离端继续

现在切换到气隙 VM 进行剩余的安装过程。

切换到 ~/tmp

cd ~/tmp

提取并移动 helm 二进制文件

tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm

将 Podinfo 容器镜像加载到本地 Docker 仓库

docker load -i podinfo_podinfo-6.4.0.tar
docker tag podinfo/podinfo:6.4.0 localhost:5000/podinfo/podinfo:6.4.0
docker push localhost:5000/podinfo/podinfo:6.4.0

确保正确设置了“$KUBECONFIG”,然后安装 Podinfo Helm 图表

# Outside of a demo or lab environment, use lower (or even least) privilege
# credentials to manage your workloads.
export KUBECONFIG=/etc/kubernetes/admin.conf
helm install podinfo ./podinfo-6.4.0.tgz --set image.repository=localhost:5000/podinfo/podinfo

验证 Podinfo 应用程序是否启动

kubectl get pods -n default

或者运行 k9s(Kubernetes 的终端用户界面)

k9s

Zarf

Zarf 是一款开源工具,它采用声明式方法进行软件包和交付,包括气隙环境。在本节中,将使用 Zarf 将同一个 podinfo 应用程序安装到气隙 VM 上。第一步是在主机/笔记本电脑上安装 Zarf

或者,可以从 GitHub 下载各种 OS/CPU 架构的预构建二进制文件到主机/笔记本电脑上。

气隙 VM 上也需要一个二进制文件

UARCH=$(uname -m)
# Set the architecture variables if needed
if [["$UARCH" == "arm64" || "$UARCH" == "aarch64"]]; then

    ARCH="aarch64"
    K8s_ARCH="arm64"

else

    ARCH="x86_64"
    K8s_ARCH="amd64"

fi

export ZARF_VERSION=v0.28.3

curl -LO "https://github.com/defenseunicorns/zarf/releases/download/${ZARF_VERSION}/zarf_${ZARF_VERSION}_Linux_${K8s_ARCH}"

Zarf 需要通过使用 init 包将其自身引导到 Kubernetes 集群中。该 init 包也需要通过气隙传输,因此让我们将其下载到主机/笔记本电脑上

curl -LO "https://github.com/defenseunicorns/zarf/releases/download/${ZARF_VERSION}/zarf-init-${K8s_ARCH}-${ZARF_VERSION}.tar.zst"

Zarf 的声明式方式是通过使用 zarf.yaml 文件来实现的。以下是用于此 Podinfo 安装的 zarf.yaml 文件。将其写入主机/笔记本电脑上您有写入权限的任何目录;您的主目录即可

echo 'kind: ZarfPackageConfig
metadata:
    name: podinfo
    description: "Deploy helm chart for the podinfo application in K8s via zarf"
components:
    - name: podinfo
        required: true
        charts:
            - name: podinfo
              version: 6.4.0
              namespace: podinfo-helm-namespace
              releaseName: podinfo
              url: https://stefanprodan.github.io/podinfo
        images:
        - ghcr.io/stefanprodan/podinfo:6.4.0' > zarf.yaml

下一步是构建 Podinfo 包。这必须从 zarf.yaml 文件所在的同一目录位置完成。

zarf package create --confirm

此命令将下载定义的 Helm 图表和镜像,并将它们放入写入磁盘的单个文件中。这个单独的文件是需要通过气隙传输的全部内容

ls zarf-package-*

示例输出

zarf-package-podinfo-arm64.tar.zst

将 Linux zarf 二进制文件、zarf init 包和 Podinfo 包传输到气隙 VM

scp -i <<SSH_KEY>> <<FILE>> <<AIRGAP_VM_USER>>@<<AIRGAP_VM_IP>>:~/tmp/

从气隙 VM 中,切换到所有工件放置的 ~/tmp 目录

cd ~/tmp

$KUBECONFIG 设置为具有本地集群凭据的文件;同时设置 Zarf 版本

export KUBECONFIG=/etc/kubernetes/admin.conf

export ZARF_VERSION=$(zarf version)

使 zarf 二进制文件可执行,并(以 root 用户身份)将其移动到 /usr/bin

chmod +x zarf && sudo mv zarf /usr/bin

同样,将 Zarf init 包移动到 /usr/bin

mv zarf-init-arm64-${ZARF_VERSION}.tar.zst /usr/bin

将 Zarf 初始化到集群中

zarf init --confirm --components=git-server

此命令完成后,Zarf 包即可部署。

zarf package deploy

此命令将搜索当前目录中的 Zarf 包。选择 podinfo 包 (zarf-package-podinfo-${K8s_ARCH}.tar.zst) 并继续。包部署完成后,运行 zarf tools monitor 以启动 k9s 来查看集群。

结论

这是一种可用于启动气隙集群的方法,以及两种部署任务应用程序的方法。在不同的操作系统上,关于需要通过气隙传输的确切软件工件,结果可能会有所不同,但从概念上讲,此过程仍然有效。

此演示还创建了一个人为的气隙环境。在现实世界中,每个遗漏的依赖项都可能意味着花费数小时(如果不是几天或几周)的时间才能使软件在气隙环境中运行。这种人为的气隙也掩盖了一些常见的气隙软件交付方法,例如使用数据二极管。根据环境的不同,二极管的使用成本可能非常高昂。此外,在传输到气隙之前,没有对任何工件进行扫描。通常,气隙的存在意味着在那里运行的工作负载更敏感,除非已知是安全的,否则不应传输任何内容。