注意:

使用 OCI Pulumi 提供商构建 Container Engine for Kubernetes (OKE) 集群

简介

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

Pulumi 是一个现代化的基础设施即代码平台,允许您使用熟悉的编程语言和工具来构建、部署和管理云基础设施。适用于 Pulumi 的 Oracle Cloud Infrastructure (OCI) 提供商可用于预配 OCI 中可用的任何资源。OCI 提供程序必须配置有身份证明才能在 OCI 中部署和更新资源。

本教程概述如何使用 OCI Pulumi 提供商来管理基础设施即代码。您将学习如何使用 Python 作为开发语言来预配 OKE 集群。

目标

先决条件

任务 1:创建 Pulumi 堆栈

每个 Pulumi 程序都部署到一个堆栈中。堆栈是 Pulumi 程序的独立可配置实例。堆栈通常用于表示开发的不同阶段(例如开发、暂存和生产)或功能分支(例如 features-x-dev)。

创建主目录

为堆栈创建一个起始目录,用于存储状态文件和堆栈源代码。

$> mkdir pulumi-oke-py && cd pulumi-oke-py   (on Linux or MacOS )

创建状态资料档案库

Pulumi 将堆栈的状态存储在 Pulumi 服务或本地状态文件中,可跟踪基础设施的更改。在本教程中,我们将将其存储在本地状态文件中。

选项 1。创建本地状态文件目录

此选项将创建一个用于存储状态的本地目录。对于本教程,将配置选项 1。

$> mkdir oci-stack-statefile (on Linux or MacOS )
$> pulumi login file://oci-stack-statefile

选项 2。在 Pulumi 免费服务中存储状态

Pulumi 提供用于存储堆栈状态的服务。从免费到组织,还有多个层。

$> pulumi login

注意:对于本教程,我们将只在本地保存状态文件,如选项 1 中所述。选项 2 仅用于附加信息。

新建 Python 堆栈

  1. 通过运行 whoami 命令确认要使用的服务和用户。

    $> pulumi whoami -v
    
    User: <user>
    Organizations:
    Backend URL: file://oci-stack-statefile
    
  2. 创建堆栈时,Pulumi 需要了解要用于项目的模板类型。

    • 当我们要在 Python 中编写代码时,您必须通过在关键字“pulumi new”之后传递模板“python”的名称来选择 Python 模板。
    • Pulumi CLI 将提示您输入项目名称(默认为父文件夹的名称)和特定环境(默认为 dev),以帮助您对堆栈进行分类和分类。
    $>pulumi new python --force
    
    This command will walk you through creating a new Pulumi project.
    
    Enter a value or leave blank to accept the (default), and press <ENTER>.
    Press ^C at any time to quit.
    
    project name: (pulumi-oke-py)
    project description: (A minimal Python Pulumi program)
    Created project 'pulumi-oke-py'
    
    stack name: (dev)
    Created stack 'dev'
    Enter your passphrase to protect config/secrets:
    Re-enter your passphrase to confirm:
    
    Failed to resolve python version command: fork/exec $PATH/pulumi-oke-py/venv/bin/python: no such file or directory
    
    Installing dependencies...
    
    Creating virtual environment...
    Finished creating virtual environment
    Updating pip, setuptools, and wheel in virtual environment...
    Collecting pip
    Using cached https://files.pythonhosted.org/packages/96/2f/caec18213f6a67852f6997fb0673ae08d2e93d1b81573edb93ba4ef06970/pip-22.1.2-py3-none-any.whl
    Collecting setuptools
    Using cached https://files.pythonhosted.org/packages/e9/1c/ec080fde54ab30a738c92f794eab7f5d2f354f2b619ee95b2efe353e0766/setuptools-62.3.2-py3-none-any.whl
    Collecting wheel
    Using cached https://files.pythonhosted.org/packages/27/d6/003e593296a85fd6ed616ed962795b2f87709c3eee2bca4f6d0fe55c6d00/wheel-0.37.1-py2.py3-none-any.whl
    Installing collected packages: pip, setuptools, wheel
    .....
    Collecting grpcio~=1.33
    Using cached grpcio-1.46.3-cp37-cp37m-macosx_10_10_x86_64.whl (4.3 MB)
    Installing collected packages: six, semver, pyyaml, protobuf, dill, grpcio, pulumi
    Successfully installed dill-0.3.5.1 grpcio-1.46.3 protobuf-3.20.1 pulumi-3.33.2 pyyaml-5.4.1 semver-2.13.0 six-1.16.0
    Finished installing dependencies
    
    Your new project is ready to go! ✨
    
    To perform an initial deployment, run 'pulumi up'
    
    

    注:当将状态文件存储在与堆栈相同的路径中时,需要使用选项 -force,因为目录不为空(它包含拉菜单状态文件文件夹)。

  3. 现在,您将运行初始部署。保持在上一步中输入的口令短语很方便。

       $> pulumi up
       Enter your passphrase to unlock config/secrets
          (set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):
       Previewing update (dev):
          Type                 Name             Plan
       +   pulumi:pulumi:Stack  pulumi-oke-py-dev  create
    
       Resources:
          + 1 to create
    
       Do you want to perform this update? yes
       Updating (dev):
          Type                 Name             Status
       +   pulumi:pulumi:Stack  pulumi-oke-py-dev  created
    
       Resources:
          + 1 created
    
       Duration: 1s
    
  4. 使用以下命令确认环境已创建。

    注意:在本地正确创建并存储模板后,Pulumi 还将使用您的 Python 程序使用的站点软件包创建 Python 虚拟 (venv) 环境。此教程的虚拟环境不在范围内。

    -rw-r--r--. 1 <user> oci 45 May 23 20:07 __main__.py
    -rw-r--r--. 1 <user> oci 117 May 23 20:07 Pulumi.yaml
    -rw-r--r--. 1 <user> oci 21 May 23 20:07 requirements.txt
    -rw-r--r--. 1 <user> oci 21 May 23 20:07 Pulumi.dev.yaml
    drwxr-xr-x. 5 <user> oci 100 May 23 20:08 venv
    drwxr-xr-x. 5 <user> oci 100 May 23 20:06 oci-stack-statefile
    
    • __main__py :Python 应用程序的入口点,这是 Pulumi 将扫描的。

    • Pulumi.yaml:堆栈描述符。

    • Pulumi.dev.yaml:堆栈环境配置。

    • requirements.txt:定义标准文件以列出管道 python 所需的软件包。

    • venv:Python 虚拟环境。

任务 2:配置 Python 虚拟环境

Pulumi 已注册 OCI 提供商,它可通过管道访问。pip 是用于安装现有库的 Python 软件包管理器。让我们安装它,但仅在虚拟环境中。

  1. 使用以下命令激活 Python 虚拟环境。

    $>  source venv/bin/activate
    
  2. 使用管道安装 pulumi_oci 软件包。

    (venv) j2joi@cloudshell:pulumi-oke-py (us-ashburn-1)$  pip install pulumi_oci
    
  3. 为 Pulumi 配置 OCI 提供程序。

    注意:Pulumi 将在其自己的配置服务中存储配置详细信息。必须为 Pulumi 配置 OCI 提供者才能对您的租户进行验证。收集用户配置文件、API 密钥、用户 ocid、租户 ocid、区域,并将其存储为脉冲环境配置中的机密。请注意,您将它们作为密钥传递,因此将使用您在创建环境时提供的密码短语加密。

    $> pulumi config set oci:tenancyOcid "ocid1.tenancy.oc1..<unique_ID>" --secret  
    $> pulumi config set oci:userOcid "ocid1.user.oc1..<unique_ID>" --secret
    $> pulumi config set oci:fingerprint "<key_fingerprint>" --secret
    $> pulumi config set oci:region "<target region in OCI>"
    $> cat "~/.oci/oci_api_key.pem" | pulumi config set oci:privateKey --secret
    $> pulumi config set compartment_ocid "ocid1.compartment.oc1..aaaaaaaaqiuXXXXXXXXXX"
    

    提示:

    • 使用口令短语值导出 PULUMI_CONFIG_PASSPHRASE。它将节省时间,而不是在每次添加密钥时提供它。
    • OCI 配置值可以直接从环境变量中读取,格式为 TF_VAR_${var_name}。
  4. 确认密钥存储在配置存储中。

    $> (venv) j2joi@cloudshell:pulumi-oke-py (us-ashburn-1)$  pulumi config
    
    KEY VALUE
    oci:fingerprint [secret]
    oci:privateKey [secret]
    oci:region us-ashburn-1
    oci:tenancyOcid [secret]
    oci:userOcid [secret]
    

    注意:Pulumi 使用两种主要变量类型,输入 [T] 和输出 [T] 类型为 T。Input[T] 是基本 Python 数据类型的原始值的包装器(String、boolean、Dict、Sequence),在创建资源后,Output 会保存未来的值。

    如果您尝试通过将输出传递给任何 Python 标准库来处理输出的值,即尝试拆分资源输出 [String] 名称,例如 name.split(),请记住这一点,因为它最终会出错,因为类型的“输出”名称变量不支持拆分。

  5. 创建第一个 OKE 群集。在开始编码之前,以下代码片段需要创建现有的虚拟云网络。OKE 的子网应具有 Kubernetes 端点、Worker 节点和负载平衡器服务所需的 3 个子网。有关 OKE 的子网要求的更多信息,例如策略、路由,请参见 OCI 文档

    让我们一起查看 OCI 集群 Python 变量定义:

    Type: pulumi_oci.containerengine.Cluster
    
    Arguments:
    
       - compartment_id : This is the Oracle Cloud Identifier OCID linked to the target compartment.
       - kubernetes_version : Update with the Kubernetes main stream versions that are supported in OCI.
       - name: This is the Kubernetes cluster displayed name.
       - options: Network CIDRs for different services and a list of subnets used for loadbalancer services, wrapped in a ClusterOptionsKubernetesNetworkConfigArgs object.
       - endpoint_config - Define if the cluster Kubernetes endpoint will have a public IP address and which subnet it will be attached to.
       - vcn_id - Virtual cloud network the Kubernetes cluster will be attached to.
    
  6. OCI VCN 准备就绪并且您具有 VCN、子网和区间 OCID 详细信息后,继续使用以下代码片段编辑 __main__.yaml 文件。使用相应的 OCID 更新值。

     "A Python Pulumi program"
     import pulumi
     import pulumi_oci as oci
    
     config = pulumi.Config()
    
     target_compartment_ocid = "ocid1.compartment.oc1.iad.XXXXXXX"
    
     subnets_lb_ocid= ["ocid1.subnet.oc1.iad.aaaaaaaan6fXXXXXXXXX"]
    
     subnet_workernodes_ocid = "ocid1.subnet.oc1.iad.aaaaaaaakYYYYYYY"
    
     subnet_endpoint_ocid = "ocid1.subnet.oc1.iad.aaaaaaaaxmfZZZZZZZZZ"
    
     vcn_ocid="ocid1.vcn.oc1.iad.amaaaaaadoggtjaasym4AAAAAAAAAA"
    
     kubernetes_version="v1.23.4"
    
     oke_cluster_opts_args = oci.containerengine.ClusterOptionsArgs(
     kubernetes_network_config=oci.containerengine.ClusterOptionsKubernetesNetworkConfigArgs(
     pods_cidr="10.244.0.0/16",
     services_cidr="10.96.0.0/16"),
     service_lb_subnet_ids = subnets_lb_ocid
     )
    
     oke_cluster = oci.containerengine.Cluster("oke_cluster",
     compartment_id = target_compartment_ocid,
     kubernetes_version = kubernetes_version,
     name = "firstPulumiPy_OKE",
     options = oke_cluster_opts_args,
     endpoint_config = oci.containerengine.ClusterEndpointConfigArgs(
     is_public_ip_enabled = True,
     subnet_id = subnet_endpoint_ocid),
     vcn_id = vcn_ocid,
     )
     pulumi.export("oke_cluster_ocid", oke_cluster)
    

    提示:您可以从 Pulumi 配置存储请求资源 ocids 将您的代码重用于其他环境,而不是直接在 Python 代码中分配 ocid 值。

    注:缩进对于 Python 是必不可少的。确保您的代码遵循 Python 缩进。

  7. 查看基础结构更改:Pulumi 可以选择预览当前堆栈将要创建/修改的资源。运行 "pulumi preview" 选项以验证当前的 python 堆栈。

    (venv) j2joi@cloudshell:pulumi-oke-py (us-ashburn-1)$ pulumi preview
    Previewing update (dev)
    
         Type                            Name               Plan       Info
     +   pulumi:pulumi:Stack             pulumi-oke-py-dev  create     1 message
     +   └─ oci:ContainerEngine:Cluster  oke_cluster        create     
    
  8. 对基础结构应用更改:如果未显示错误消息,则可以创建 OKE 集群。运行 "pulumi up" 以触发堆栈以应用更改。

    (venv) j2joi@cloudshell:pulumi-oke-py (us-ashburn-1)$ pulumi up
    Updating (dev)
    
         Type                            Name               Status      Info
     +   pulumi:pulumi:Stack             pulumi-oke-py-dev  created     12 messages
     +   └─ oci:ContainerEngine:Cluster  oke_cluster        created
    
  9. 添加 OKE 节点池资源:Pulumi Stack 创建了第一个 OKE 集群 "oke_cluster"。现在,让我们在同一个 main.py 文件中添加分配给节点池变量的 worker 节点。更改将以增量方式添加到 OCI 中的资源集,因为 Pulumi 会跟踪创建的资源,并将比较云提供商内部资源与所选后端中存储的状态之间的任何差异,以验证是否需要对现有资源或新资源进行更新。

    Worker node Compute Instance details
    number_worker_nodes= 3
    default_node_memory_size=16
    default_node_num_ocpus =1
    
    # Get the Availability Domain names for this region
    ad_list=oci.identity.get_availability_domains(target_compartment_ocid)
    ad=ad_list.availability_domains
    
    # Get the list of supported images based on the compartment and filter it by most recent image
    list_of_supported_image =oci.core.get_images(compartment_id=target_compartment_ocid,
                                          operating_system="Oracle Linux",
                                          operating_system_version= "7.9",
                                          shape= "VM.Standard.E3.Flex",
                                          sort_by="TIMECREATED",
                                          sort_order="DESC"
                                          )
    #Obtain the first image ocid from  list_of_supported_image var
    os_image_ocid= list_of_supported_image.images[0].id
    
    # Pin for this example all worker nodes to a first Availability Domain
    place_nodes_subnet=[oci.containerengine.NodePoolNodeConfigDetailsPlacementConfigArgs(
                    availability_domain=ad[0].name,
                    subnet_id= subnet_workernodes_ocid
                ),]
    
    #Declare all Pool properties
    node_pool_args = oci.containerengine.NodePoolArgs(cluster_id=oke_cluster.id,
                                                          compartment_id= target_compartment_ocid,
                                                          kubernetes_version=kubernetes_version,
                                                          node_shape= "VM.Standard.E3.Flex",
                                                          name="E3Flex",
                                                          node_config_details=oci.containerengine.NodePoolNodeConfigDetailsArgs(
                                                              placement_configs= place_nodes_subnet ,
                                                              size= number_worker_nodes
                                                          ),
                                                          node_shape_config=oci.containerengine.NodePoolNodeShapeConfigArgs(
                                                              memory_in_gbs= default_node_memory_size,
                                                              ocpus= default_node_num_ocpus,
                                                          ),
                                                          node_source_details=oci.containerengine.NodePoolNodeSourceDetailsArgs(
                                                              image_id= os_image_ocid,
                                                              source_type="IMAGE",
                                                              boot_volume_size_in_gbs=60,
                                                          ),
                                                          )
    #Assign node pool properties as args to node_pool
    node_pool = oci.containerengine.NodePool("nodepool", args=node_pool_args)
    
    pulumi.export("oke_cluster_ocid", oke_cluster)
    pulumi.export("oke_node_pool", node_pool)
    
  10. 运行“pulumi up”命令再次更新您的基础结构。

    $> pulumi up
    

其他信息

Pulumi Marketplace 已有一些其他现有提供商可供您使用,例如 Kubernetes、Helm 等。在 Oracle Cloud 中创建资源(例如 Kubernetes)的优势之一是它与大多数 Kubernetes 标准兼容,并且集成非常简单。以下示例说明如何使用 Pulumi 的提供商创建您自己的 Kubernetes 提供商,以及在您的 Python 代码中部署应用。

import pulumi_kubernetes

kubeconfig = oci.containerengine.get_cluster_kube_config_output(cluster_id=oke_cluster.id).apply(
   lambda kube_config: kube_config.content)

k8sProvider = pulumi_kubernetes.Provider("okeK8s",
                                        kubeconfig=kubeconfig
                                        )


pulumi.export("kubeconfig", kubeconfig)

任务 3:删除资源

您已经使用 Pulumi 的 OCI 提供商完成了您的首个 Python 堆栈。要删除所有资源,请运行肺部销毁命令。

$> pulumi destroy

pulumi destroy
Previewing destroy (dev):
     Type                            Name             Plan
 -   pulumi:pulumi:Stack             local-state-dev  delete
 -   └─ oci:ContainerEngine:Cluster  oke_cluster      delete

致谢

更多学习资源

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

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