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

使用 Kubeadm 引导气隙集群

是否曾想过如何将软件部署到与互联网和其他网络刻意断开连接的系统上?这些系统通常因其敏感性质而断开连接。敏感性例如公用事业(电力/供水)、银行、医疗保健、武器系统、其他政府用例等。有时候,如果你在水下航行器上运行 Kubernetes,这在技术上是水隙。尽管如此,这些环境仍然需要软件来运行。这种在断开连接状态下进行部署的概念,就是部署到物理隔离的另一侧。

同样,尽管采取了这种姿态,软件仍然需要在这些环境中运行。传统上,软件制品是通过硬盘、USB 盘、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

本地拓扑

这台虚拟机的网络连接将被禁用,但禁用方式不会关闭虚拟机的虚拟网卡。相反,它的网络将通过向一个 dummy 接口注入默认路由而断开,使得任何互联网托管的内容都无法访问。然而,虚拟机仍然与主机的桥接接口有一个连接路由,这意味着与主机的网络连接仍然有效。这种姿态意味着数据可以通过 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 registry 容器镜像
  • Kubernetes 组件容器镜像
  • CNI 网络插件容器镜像(本次实验将使用 Flannel
  • CNI 网络插件 manifests
  • 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 设置为使用旧模式(而非 nft 模拟 iptables

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

关闭 swap

touch /etc/systemd/zram-generator.conf
systemctl mask systemd-zram-setup@.service
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 配置文件中有两点重要内容需要强调。insecure-registries 行意味着括号中的注册表不支持 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 注册表来存放 K8s 组件镜像?”即使对传递给 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

从物理隔离虚拟机内部登录 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 server 变为健康状态

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 manifest 中的 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,请按照 安装 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 chart,下载 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/

在隔离侧继续

现在切换到物理隔离虚拟机,执行剩余的安装过程。

切换到 ~/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 chart

# 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 应用程序安装到物理隔离虚拟机上。第一步是在主机/笔记本电脑上安装 Zarf

或者,可以从 GitHub 下载针对不同操作系统/CPU 架构的预编译二进制文件到主机/笔记本电脑上。

还需要在物理隔离的虚拟机上有一个二进制文件

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 集群中。这个包也需要跨越物理隔离传输,所以让我们将其下载到主机/笔记本电脑上

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 chart 和镜像,并将它们放入一个写入磁盘的单个文件中。只需将此单个文件跨越物理隔离传输即可

ls zarf-package-*

示例输出

zarf-package-podinfo-arm64.tar.zst

将 linux zarf 二进制文件、zarf init 包和 Podinfo 包传输到物理隔离虚拟机

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

从物理隔离虚拟机,切换到存放所有制品的 ~/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 查看集群。

结论

这是用于启动物理隔离集群的一种方法以及部署任务应用程序的两种方法。在不同的操作系统上,需要跨越物理隔离传输的具体软件制品可能会有所不同,但从概念上讲,此过程仍然有效。

此演示还创建了一个人工物理隔离环境。在现实世界中,每一个遗漏的依赖项都可能导致物理隔离环境中运行软件耗费数小时、甚至数天或数周的时间。这种人工物理隔离也掩盖了一些常见的物理隔离软件交付方法,例如使用数据二极管。根据环境不同,使用二极管可能非常昂贵。此外,在跨越物理隔离传输之前,没有对任何制品进行扫描。总的来说,物理隔离的存在意味着在此运行的工作负载更敏感,除非已知安全,否则不应传输任何内容。