我在Pulumi (Python)中尝试使用Kubernetes部署Pods / Helm Chart

以下是一位Pulumi初学者在学习Kubernetes并进行评估时的笔记。由于官方文档以TypeScript为主,Python的示例较少,所以特别记录下Python的示例。

概要

如标题所述,我在Pulumi上试评了Kubernetes的部署。以下是我的主要感受。

    • Kubernetes用のテンプレート(kubernetes-python)が提供されているため、比較的導入のしきいは低い(プロジェクトの初期状態からpulumi upする程度で、シンプルなnginxのdeploymentが作成できる)。

kubectlコマンドが叩ける状態になっていれば、特に追加の設定はなさそう。

PulumiのHelm Chartデプロイ機能は、単純にHelmをKickするだけでなく、独自にServideやDeploymentなどのリソースを展開&解釈してデプロイしている。このため、Helm 2.xでもTiller Serverが不要。

今回はHelm 3.xを利用したためこの恩恵は受けられず、逆にhelm listコマンドで内容を確認できないデメリットもあり。

Pulumi.Output(生成されたリソースの出力用パラメータ)の変換実装には、相応に試行錯誤が必要だった(apply関数の周りなどの理解がある程度難しい)。

実装コードは逐次処理のPythonコードに見えるが、内部的には(PreviewやDiff制御など)宣言的な概念も扱っているため、若干理解し辛い側面もありそう。

评价

假设

假设Kubernetes集群(使用AWS EKS)已经构建完成,并且Plumi和Helm的初始设置也已经完成。
测试所使用的Helm Chart(bitnami/jenkins)的仓库也已经预先注册(虽然可以通过FetchOps类的功能从仓库中获取,但本次评估的目标将其排除在外)。

$ pulumi version
v1.8.1
$ kubectl get nodes
NAME                                            STATUS   ROLES    AGE     VERSION
ip-10-0-0-145.ap-northeast-1.compute.internal   Ready    <none>   1h51m   v1.14.7-eks-1861c5
ip-10-0-2-96.ap-northeast-1.compute.internal    Ready    <none>   1h50m   v1.14.7-eks-1861c5
$ helm version
version.BuildInfo{Version:"v3.0.2", GitCommit:"19e47ee3283ae98139d98460de796c1be1e3975f", GitTreeState:"clean", GoVersion:"go1.13.5"}

$ helm repo list
NAME    URL
bitnami https://charts.bitnami.com/bitnami

项目初始化

使用kubernetes-python模板,创建一个新的Pulumi项目(使用默认回答回答问题)。

$ mkdir python-k8s && cd python-k8s
$ pulumi new kubernetes-python

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: (python-k8s)
 project description: (A minimal Kubernetes Python Pulumi program)
 Created project 'python-k8s'

 Please enter your desired stack name.
 To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
 stack name: (dev)
 Created stack 'dev'

 Your new project is ready to go! ✨

 To perform an initial deployment, run the following commands:

    1. virtualenv -p python3 venv
    2. source venv/bin/activate
    3. pip3 install -r requirements.txt

 Then, run 'pulumi up'

按照消息所显示的,进行Python虚拟环境的配置(以及安装依赖库)。

$ pip3 install virtualenv
$ virtualenv -p python3 venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt

实施

将Python的实现代码(__main__.py)更改为创建以下两种资源。请注意,Output字段应定义为输出每个服务的主机名(分配给AWS Elastic Load Balancer的主机名)。

    • NGINX Deployment / Service

NGINXのdeploymentと、外部公開用のLoadBalancer TypeのService。

Jenkins Helm Chart

bitnami/jenkinsのHelm Chart。

import base64
import pulumi
from pulumi_kubernetes.apps.v1 import Deployment
from pulumi_kubernetes.core.v1 import Service
from pulumi_kubernetes.helm.v2 import Chart, ChartOpts

def deploy_nginx_service():
    app_name = "nginx"
    app_labels = { "app": app_name }

    nginx_deployment = Deployment(
        app_name,
        spec={
            "selector": { "match_labels": app_labels },
            "replicas": 1,
            "template": {
                "metadata": { "labels": app_labels },
                "spec": { "containers": [{ "name": app_name, "image": "nginx" }] }
            }
        })

    nginx_service = Service(
        app_name,
        metadata={
            "labels": nginx_deployment.spec["template"]["metadata"]["labels"],
        },
        spec={
            "type": "LoadBalancer",
            "ports": [{ "port": 80, "target_port": 80, "protocol": "TCP" }],
            "selector": app_labels,
        })

    return nginx_service

def deploy_jenkins_chart():
    return Chart("jenkins", ChartOpts(
        chart="jenkins",
        repo="bitnami",
        values={},
    ))

nginx_service = deploy_nginx_service()
jenkins_chart = deploy_jenkins_chart()

pulumi.export("nginx_hostname",
    nginx_service.status.apply(
        lambda x: x["load_balancer"]["ingress"][0]["hostname"]))

pulumi.export("jenkins_hostname",
    jenkins_chart.resources.apply(
        lambda x: x["v1/Service:jenkins"].status["load_balancer"]["ingress"][0]["hostname"]))

执行

pulumi up
Previewing update (dev):

     Type                                         Name            Plan
 +   pulumi:pulumi:Stack                          python-k8s-dev  create
 +   ├─ kubernetes:helm.sh:Chart                  jenkins         create
 +   │  ├─ kubernetes:core:PersistentVolumeClaim  jenkins         create
 +   │  ├─ kubernetes:core:Secret                 jenkins         create
 +   │  ├─ kubernetes:core:Service                jenkins         create
 +   │  └─ kubernetes:apps:Deployment             jenkins         create
 +   ├─ kubernetes:apps:Deployment                nginx           create
 +   └─ kubernetes:core:Service                   nginx           create

Resources:
    + 8 to create

Do you want to perform this update? yes
Updating (dev):

     Type                                         Name            Status
 +   pulumi:pulumi:Stack                          python-k8s-dev  created
 +   ├─ kubernetes:helm.sh:Chart                  jenkins         created
 +   │  ├─ kubernetes:core:Secret                 jenkins         created
 +   │  ├─ kubernetes:core:Service                jenkins         created
 +   │  ├─ kubernetes:core:PersistentVolumeClaim  jenkins         created
 +   │  └─ kubernetes:apps:Deployment             jenkins         created
 +   ├─ kubernetes:apps:Deployment                nginx           created
 +   └─ kubernetes:core:Service                   nginx           created

Outputs:
    jenkins_hostname: "xxx.ap-northeast-1.elb.amazonaws.com"
    nginx_hostname  : "yyy.ap-northeast-1.elb.amazonaws.com"

Resources:
    + 8 created

根据Outputs中输出的主机名,分别对应jenkins和nginx的服务(负载均衡器)。当使用curl访问时,每个服务都会返回响应。

$ curl -s --head xxx.ap-northeast-1.elb.amazonaws.com | grep X-Jenkins:
X-Jenkins: 2.204.1
$ curl -s --head yyy.ap-northeast-1.elb.amazonaws.com | grep Server
Server: nginx/1.17.6

资源确认

通过使用`kubectl`命令,您可以确认生成的资源。然而,由于Pulumi对Helm Chart进行了自定义展开,因此不会显示(列表为空)。

$ kubectl get deployments
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
jenkins          1/1     1            1           32m
nginx-nziiq5rs   1/1     1            1           32m
$ kubectl get services
NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                            PORT(S)                      AGE
jenkins          LoadBalancer   172.20.125.15   xxx.ap-northeast-1.elb.amazonaws.com   80:32525/TCP,443:31321/TCP   33m
kubernetes       ClusterIP      172.20.0.1      <none>                                 443/TCP                      1h42m
nginx-6hbjq6d7   LoadBalancer   172.20.14.82    yyy.ap-northeast-1.elb.amazonaws.com   80:32325/TCP                 33m
$ helm list
NAME    NAMESPACE   REVISION    UPDATED STATUS  CHART   APP VERSION

以下是一份参考资料。

    Pulumi Kubernetes

Kubernetes的插件说明。

    Docs Reference API pulumi_kubernetes

API参考文档。

    Pulumi Kubernetes WordPress Helm Chart

在本教程中,我们将使用 @pulumi/kubernetes 的Helm API将v2.1.3版本的Wordpress Helm Chart部署到一个Kubernetes集群中。不需要安装Tiller服务器。Pulumi将展开Helm Chart并将展开的YAML提交到集群中。

Pulumi的Helm提供程序通过独自展开和部署Chart来解释。由于这个原因,helm list命令的结果中没有任何输出。

    Docs – Intro to Pulumi – Architecture & Concepts – Programming Model – apply

对于Output的输出转换的解释。
在对Pulumi输出的Output(Pulumi.Output类型)进行处理时,需要使用apply函数(可能在内部进行了特殊处理,或者简单地进行对象转换可能导致无法正常工作。例如,可能会遇到阻塞pulumi up等处理,导致处理无法继续进行的现象)。

apply 方法接受一个回调函数,当 Output 可用时,回调函数将被传递 Output 的值,并返回新的值。apply 被调用后的结果是一个新的 Output,其值是从回调函数返回的值,并包括原始 Output 的依赖关系。如果回调函数本身返回一个 Output,则该输出的依赖关系将与返回的 Output 的依赖关系合并。

广告
将在 10 秒后关闭
bannerAds