本篇文章將會接續前面文章,前面已經介紹如何部署 EKS Cluster,並設定 NodeGroup 執行 worker node。今天就要在 K8S 內執行應用程式。
今天會用到 Kubernetes Provider,這是 Pulumi 用來控制 K8S 資源的 Provider。可以透過套件管理工具安裝 Provider。
$ npm install @pulumi/kubernetes
安裝好後,就可以 import provider。
import * as k8s from '@pulumi/kubernetes';
與 AWS Provider 相同,K8S provider 預設會讀取 ~/kube/config
的資訊做為預設的 K8S Cluster,所有的操作都會在該 cluster 中進行。但在這個練習中,要使用 EKS Cluster 做為 Cluster。因此可以產生 kubeconfig ,並建立屬於這個 Cluster 的 Provider。
const k8sProvider = new k8s.Provider(`my-provider`, {
kubeconfig: eksCluster.getKubeconfig(),
});
建立了 Provider 之後,就可以在 k8s resource 的 opts 參數中,設定 provider 參數,並傳入前面設定的 provider。
例如以下範例會建立一個 namespace,名字為 test-namespaces,並且使用 EKS Cluster 的 kubeconfig 所建立的 K8S Provider。
const ns = new k8s.core.v1.Namespace('project-namespace', {
apiVersion: 'v1',
kind: 'Namespace',
metadata: {
name: 'test-namespaces',
}
}, {provider: k8sProvider});
接著來建立一個 sample application,這邊參考的範例為 AWS 文件的範例應用程式。
首先,建立 Component Resource 類別,與之前的練習一樣,將整個 Application 包裝成一個 Component Resource。
這邊簡單的讓 user 傳入 kubeconfig 就行,其他的資訊先寫死在類別中,有需要再變成參數讓使用者可以變更。
interface K8SSampleAppArgs {
kubeConfig: pulumi.Input<string>;
}
export class K8SSampleApp extends pulumi.ComponentResource {
constructor(name: string, args: K8SSampleAppArgs, opts: pulumi.ComponentResourceOptions = {}) {
super('pulumi-practice:k8s_sample_app:K8SSampleApp', name, args, opts);
}
}
接著在建構子中,直接建立 Provider,之後所有的 K8S 資源都會使用這個 Provider。
this.provider = new k8s.Provider(`${name}-provider`, {
kubeconfig: args.kubeConfig,
});
Pulumi 的 kubernetes Provider 的使用方式與直接寫 YAML 的結構差不多,只是將 YAML 改成類似 JSON 的樣子來撰寫 (説類似 JSON 是因為在這是使用 JavaScript Object,差別在於 JS 的 Object 寫起來比 JSON 自由度高一點,key 不需要加引號)。不過用 Pulumi 撰寫有個好處 -- 可以讓 IDE 提供 Code Completion (程式碼自動補完)、 Typing Hint (型別提示)。
在使用時,可以根據所要用的 K8S api 去找到要使用的資源類別位置。如果 apiVersion 為 v1
,則 apiVersion v1
的資源都會在 k8s.core.v1 之下。
另外像是 Deployment 的 apiVersion 為 apps/v1
,則我們可以在 k8s.apps.v1 中找到 Deployment。依此類推,如果要用 Ingress,就到 k8s.networking.v1 中去找到 Ingress。
const ns = new k8s.core.v1.Namespace('project-namespace', {
apiVersion: 'v1',
kind: 'Namespace',
metadata: {
name: 'project-namespace',
}
}, {provider: this.provider});
接著來建立 Deployment,在這我們也可以善用程式語言的功能,將重複設定的值抽成變數。這就會比去寫 Helm Chart 的 Template 還方便。
const label = {
app: 'eks-sample-linux',
};
const sampleApp = new k8s.apps.v1.Deployment('eks-sample-linux-deployment', {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: 'eks-sample-linux-deployment',
namespace: ns.metadata.name,
labels: label
},
spec: {
replicas: 3,
selector: {
matchLabels: label
},
template: {
metadata: {
labels: label
},
spec: {
nodeSelector: {
'kubernetes.io/os': 'linux',
},
affinity: {
nodeAffinity: {
requiredDuringSchedulingIgnoredDuringExecution: {
nodeSelectorTerms: [
{
matchExpressions: [
{
key: 'kubernetes.io/arch',
operator: 'In',
values: ['amd64', 'arm64']
}
]
}
]
}
}
},
containers: [
{
name: 'nginx',
image: 'public.ecr.aws/nginx/nginx:1.23',
ports: [
{
name: 'http',
containerPort: 80,
}
],
imagePullPolicy: 'ifNotPresent',
}
]
},
}
}
}, {
provider: this.provider,
dependsOn: [ns],
parent: ns,
});
最後來建立 Service 並使用 LoadBalancer Type,讓 EKS 自動建立 Load Balancer。
const svc = new k8s.core.v1.Service('eks-sample-linux-service', {
apiVersion: 'v1',
kind: 'Service',
metadata: {
name: 'eks-sample-linux-service',
namespace: ns.metadata.name,
labels: {
app: 'eks-sample-linux',
}
},
spec: {
type: 'LoadBalancer',
selector: {
app: 'eks-sample-linux',
}
}
}, {
provider: this.provider,
dependsOn: [sampleApp],
parent: ns,
});
今天的練習為部署簡單的 K8S Application,可以從練習中學習,如何在使用完 aws provider 後,又使用 k8s provider 操作其他種類的資源。學會操作簡單的資源後,就可以嘗試將既有的 Helm Chart 或是 kustomize 轉換為 pulumi 的 Component Resource。