注意:

在 OKE 上为 Kubernetes 部署 Longhorn

简介

Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) 是一个完全托管、可扩展且高度可用的服务,您可以使用它将容器化应用部署到云中。您可以指定应用所需的计算资源,OKE 可以在现有 OCI 租户中的 Oracle Cloud Infrastructure (OCI) 上预配这些资源。Container Engine for Kubernetes 使用 Kubernetes - 开源系统,可跨主机集群自动部署、扩展和管理容器化的应用。

OCI 块存储卷服务可为您的数据提供持久、持久和高性能块存储,OKE 可以将这些块存储卷用作 Kubernetes 环境的持久性磁盘,并完全由 OKE 管理。如果您希望完全控制持久性存储解决方案,可以在 OKE 上部署 Longhorn 并将其用作存储类。它允许您完全控制持久性卷、扩展、备份和调度。

目标

先决条件

任务 1:创建 OKE 集群

  1. 登录到 OCI 控制台,导航到 Oracle Container Engine for Kubernetes 并单击创建

  2. 创建集群向导中,单击定制创建

    定制创建

  3. 指定集群名称,选择要使用的 Kubernetes 版本,然后单击向导底部的下一步

    创建集群

    注:您必须先设置 VCN、子网和路由,然后才能开始创建集群

    • 您可以选择任一网络类型。VCN 本机网络可提供更高的性能。如果您选择 VCN 本机网络,请确保子网具有足够的可用 IP 地址。

      网络类型

    • 配置节点池,选择所需的计算资源。在高级选项中,粘贴以下定制 cloud-init 脚本。

      cloud-init 脚本

    • OKE 不提供修改节点模板的选项,因此,要附加块存储卷,必须在节点初始化时运行 cloud-init 脚本。该脚本将创建指定大小和性能的块存储卷,并在初始化时将其连接到节点。

    • 根据需要,确保在脚本中修改 size_in_gbs(要在 init 上附加的块存储大小)、vpus_per_gb(块存储附加的每 GB vpu)和 mode(附加模式、PARA 或 ISCSI)变量。

    您需要创建动态组并提供此组对块存储的管理访问权限,这允许我们在脚本中使用实例主体验证。

    cloud-init 脚本

    #!/bin/bash
    curl --fail -H "Authorization: Bearer Oracle" -L0 http://169.254.169.254/opc/v2/instance/metadata/oke_init_script | base64 --decode >/var/run/oke-init.sh
    bash /var/run/oke-init.sh
    
    echo "installing python3-pip , oci sdk\n"
    sudo yum install python3 -y
    sudo yum install python3-pip -y
    pip3 install oci
    pip3 install requests
    
    cat << EOF > pyscript.py
    #!/usr/bin/python
    
    import oci
    import requests
    
    size_in_gbs = 200
    vpus_per_gb = 10
    mode = 'PARA'
    device_path = "/dev/oracleoci/oraclevdb"
    signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
    compute_client = oci.core.ComputeClient({}, signer = signer)
    block_storage_client = oci.core.BlockstorageClient({}, signer = signer)
    
    def get_current_instance_details():
        r = requests.get(url= 'http://169.254.169.254/opc/v1/instance')
        return r.json()
    
    def create_volume(block_storage, compartment_id, availability_domain, display_name: str):
        print("--- creating block volume ---")
        result = block_storage.create_volume(
            oci.core.models.CreateVolumeDetails(
                compartment_id=compartment_id,
                availability_domain=availability_domain,
                display_name=display_name,
                size_in_gbs = size_in_gbs,
                vpus_per_gb = vpus_per_gb
            )
        )
        volume = oci.wait_until(
            block_storage,
            block_storage.get_volume(result.data.id),
            'lifecycle_state',
            'AVAILABLE'
        ).data
        print('--- Created Volume ocid: {} ---'.format(result.data.id))
    
        return volume
    
    def attach_volume(instance_id, volume_id,device_path):
        volume_attachment_response = ""
        if mode == 'ISCSI':
            print("--- Attaching block volume {} to instance {}---".format(volume_id,instance_id))
            volume_attachment_response = compute_client.attach_volume(
                oci.core.models.AttachIScsiVolumeDetails(
                    display_name='IscsiVolAttachment',
                    instance_id=instance_id,
                    volume_id=volume_id,
                    device= device_path
                    )
                )
        elif mode == 'PARA':
            volume_attachment_response = compute_client.attach_volume(
                oci.core.models.AttachParavirtualizedVolumeDetails(
                display_name='ParavirtualizedVolAttachment',
                instance_id=instance_id,
                volume_id=volume_id,
                device= device_path
            )
        )
    
        oci.wait_until(
            compute_client,
            compute_client.get_volume_attachment(volume_attachment_response.data.id),
            'lifecycle_state',
            'ATTACHED'
        )
        print("--- Attaching complete block volume {} to instance {}---".format(volume_id,instance_id))
        print(volume_attachment_response.data)
    
        # Call instance metadata uri to get current instace details
        instanceDetails = get_current_instance_details()
        print(instanceDetails)
        volume = create_volume(block_storage= block_storage_client, compartment_id= instanceDetails['compartmentId'], availability_domain=instanceDetails['availabilityDomain'], display_name= instanceDetails['displayName'])
        attach_volume(instance_id=instanceDetails['id'], volume_id=volume.id, device_path= device_path)
    
        EOF
    
        echo "running python script\n"
        chmod 755 pyscript.py
        ./pyscript.py
    
        echo "creating file system on volume\n"
        sudo /sbin/mkfs.ext4 /dev/oracleoci/oraclevdb
        echo "mounting volume\n"
        sudo mkdir /mnt/volume
        sudo mount /dev/oracleoci/oraclevdb /mnt/volume
        echo "adding entry to fstab\n"
        echo "/dev/oracleoci/oraclevdb /mnt/volume ext4 defaults,_netdev,nofail 0 2" |  sudo tee -a /etc/fstab
    
  4. 复查并单击创建集群,然后等待集群变为可用。

  5. 集群可用后,转到节点池,然后转到节点。您可以看到节点处于就绪状态,单击任何节点,它将打开实例详细信息页,转至附加的块存储卷,并且您可以验证块存储卷(大小和 vpu,如 cloud-init 脚本中所述)是否已附加到实例。

    块存储卷

任务 2:设置 Longhorn

  1. 集群可用后,您可以使用 Cloud Shell 访问集群,单击访问集群并在 Cloud Shell 中复制并运行命令。

    访问集群

  2. 运行 kubectl get node 以获取可调度节点的列表。

    获取节点

  3. 为了使 Longhorn 识别所连接的磁盘,我们需要向节点添加标签和注释,如 Longhorn default disk setup 中所述。为此,我们将创建一个 patch.yaml 文件来为节点打补丁。

    metadata:
    labels:
        node.longhorn.io/create-default-disk: "config"
    annotations:
        node.longhorn.io/default-disks-config: '[
        {
            "path":"/var/lib/longhorn",
            "allowScheduling":true
        },
        {
            "path":"/mnt/volume",
            "allowScheduling":true
        }
    ]'
    
  4. 对每个节点运行以下命令。

    kubectl patch node <node name> --patch-file patch.yaml

    补丁程序节点

  5. 运行 describe node 命令以验证节点是否已打补丁。

    kubectl describe node <node name>

    描述节点

任务 3:安装 Longhorn

  1. 在本教程中,我们使用 Helm 在 OKE 集群上部署 Longhorn。按照本文档中提到的说明进行操作: Install with Helm

  2. 运行以下命令来部署 Longhorn。

    helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --version 1.3.2 --set defaultSettings.createDefaultDiskLabeledNodes=true

    部署 Longhorn

    注:在部署时将 defaultSettings.createDefaultDiskLabeledNodes 属性设置为 true。这将指示 longhorn 使用我们之前提供的连接块存储卷配置。

  3. 验证 pod 是否已创建且正在运行。

    检查云池

  4. 要启用 UI 以更好地查看 Longhorn 及其管理,请安装本文档中提到的 Ingress Controller: Example:Setting Up an Ingress Controller on a Cluster

  5. 创建 ingress.yaml 文件以公开 Longhorn UI。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: longhorn-ingress
    namespace: longhorn-system
    annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
    rules:
    - http:
        paths:
            - path: /
            pathType: Prefix
            backend:
                service:
                name: longhorn-frontend
                port:
                    number: 80
    
  6. 运行 kubectl apply -f ingress.yaml 以使用 Ingress 网关公开 Longhorn UI。

    入站网关

  7. 通过运行以下命令获取网关 URL。

    kubectl get ingress -n longhorn-system.

    入站 IP

  8. 从浏览器打开 IP 地址以访问 Longhorn 控制台并确认其处于活动状态。

    Longhorn UI

    您可以看到,我们拥有可供使用的存储。

任务 4:缩放长角

Longhorn 使您可以完全控制 kubernetes 部署的存储解决方案,但扩展 longhorn 仍然是一个手动过程,您可以通过 3 种方式扩展 Longhorn 设置。

  1. 增加附加的块存储卷的大小或性能单元:这是一个手动过程,您必须单独扩展每个块存储卷,并在节点上运行一些脚本来扩展存储。有关更多信息,请参见 Resizing a Volume

  2. 附加更多卷:您必须手动创建卷并将其附加到节点。

  3. 通过增加节点来扩展集群:由于我们已经提供了 cloud-init 脚本,它将创建块存储卷并将其连接到节点。如任务 2.3 中所述,必须在节点准备就绪后对其进行修补,Longhorn 才能识别连接的存储。

注:您可以修改脚本,将所需数量的块存储卷附加到单个节点。

确认

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心