今天來練習建立 AWS EKS Cluster,AWS EKS 是 AWS 推出的 Kubernetes 代管服務,可以協助代管 K8S Control Plane。
在此,一樣使用 Component Resource 來建立一個 EKSCluster 類別。建立 Component Resource 的第一要件就是先用 Interface 來定義建立 Resource 所需要用到的參數。接著建構出 Component Resource 的雛形,將所有建立資源的程式都放在 initizlie 方法中。
interface EKSClusterArgs {
clusterName: pulumi.Input<string>;
vpcId: pulumi.Input<string>;
subnetIds: pulumi.Input<pulumi.Input<string>[]>;
version?: pulumi.Input<string>;
roleArn?: pulumi.Input<string>;
}
export class EKSCluster extends pulumi.ComponentResource {
constructor(name: string, args: EKSClusterArgs, opts: pulumi.ComponentResourceOptions = {}) {
super("pulumi-practice:vpc:Vpc", name, {name, args, opts}, opts);
}
protected async initialize({name, args, opts}: {
name: string;
args: EKSClusterArgs;
opts?: pulumi.ComponentResourceOptions;
}) {
}
}
接著就可以開始在 initialize 內撰寫建立資源的程式了!
第一個部分比較簡單,如果使用者沒有傳入 roleArn 的話,就建立一個 cluster role。
這邊參考官方文件——Amazon EKS 叢集 IAM 角色 建立 cluster iam role。
if (!args.roleArn) {
this.role = new aws.iam.Role(`${name}-eksClusterRole`, {
assumeRolePolicy: {
Version: "2012-10-17",
Statement: [
{
Action: "sts:AssumeRole",
Principal: {
Service: "eks.amazonaws.com"
},
Effect: "Allow"
}
]
}
});
}
接著需要建立 NodeGroup Iam Role,這個 IAM role 是未來要建立 NodeGroup 時,要提供的 Role。由於在這不打算讓使用者設定,因此就在 component resource 中建立。
建立的方式一樣參考自 AWS EKS 文件:Amazon EKS 節點 IAM 角色
this.nodeGroupRole = new aws.iam.Role(`${name}-eks-nodeGroupRole`, {
assumeRolePolicy: {
Version: "2012-10-17",
Statement: [
{
Action: "sts:AssumeRole",
Principal: {
Service: "ec2.amazonaws.com"
},
Effect: "Allow"
}
]
}
});
new aws.iam.RolePolicy(`${name}-eks-nodeGroupRolePolicy`, {
role: this.nodeGroupRole,
policy: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: [
"ec2:AssignIpv6Addresses",
"ec2:DescribeInstances",
"ec2:DescribeTags",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeInstanceTypes"
],
Resource: "*"
},
{
Effect: "Allow",
Action: [
"ec2:CreateTags"
],
Resource: [
"arn:aws:ec2:*:*:network-interface/*"
]
}
]
}
});
接著建立 Cluster Security Group,這個 SG 會套用至 Control Plane 與 NodeGroup 之間的流量。這邊就使用 EKS Cluster 預設的方式去放行流量。如果需要客製化規則的話,須參考 AWS 文件:Amazon EKS 安全群組與考量 放行該放行的流量。如果 API Server 與 Worker Node 無法溝通,就會無法調度 Container。
this.clusterSecurityGroup = new aws.ec2.SecurityGroup(`${name}-eks-cluster-sg`, {
vpcId: args.vpcId,
ingress: [
{
protocol: "-1",
fromPort: 0,
toPort: 0,
self: true
}
],
egress: [
{
protocol: "-1",
fromPort: 0,
toPort: 0,
cidrBlocks: ["0.0.0.0/0"],
ipv6CidrBlocks: ["::/0"]
}
]
});
現在萬事俱備只欠東風,所有相關的資源都準備好了,只剩下建立 EKS Cluster 了!這邊建立的 Cluster 為 Public + Private Endpoint。在 VPC 內會使用 Private Endpoint 連線至 Control Plane;在 VPC 之外,就只用 Public Endpoint 連線至 Cluster。
this.cluster = new aws.eks.Cluster(name, {
name: name,
roleArn: args.roleArn || this.role!.arn,
version: pulumi.output(args.version).apply(v => v || "1.27"),
vpcConfig: {
subnetIds: args.subnetIds,
clusterSecurityGroupId: this.clusterSecurityGroup.id,
endpointPrivateAccess: true,
endpointPublicAccess: true
}
});
建立完 EKSCluster 類別後,就可以來使用它建立 EKS Cluster 了。這邊我們用到了之前所建立的 Vpc 基礎設施中所公開的成員——vpc、privateSubnetIds 來建立 EKS Cluster。
const eksCluster = new EKSCluster('project-eks-cluster', {
vpcId: vpc.vpc.id,
subnetIds: vpc.privateSubnetIds,
clusterName: 'project-eks-cluster',
version: '1.26',
});
有了 Control Plance 後,還需要有 worker node 才能調度 Pod。在此,希望可以透過 EKSCluster 物件中的方法來建立 NodeGroup。
使用起來類似這樣:
eksCluster.addWorkerNode('work1', 't3.large', 3);
填入 NodeGroup 的名字、機器大小、數量,即可幫我們建立 NodeGroup。
要達到這點,我們只需要在 EKSCluster 類別中加入 addWorkerNode 方法,如下:
public addWorkerNode(
name: string,
instanceType: string,
desiredSize: number,
maxSize?: number,
minSize?: number
) {
new aws.eks.NodeGroup(name, {
instanceTypes: [instanceType],
clusterName: this.cluster!.name,
nodeRoleArn: this.nodeGroupRole.arn,
subnetIds: this.cluster!.vpcConfig.subnetIds,
scalingConfig: {
desiredSize: desiredSize,
maxSize: maxSize ?? desiredSize,
minSize: minSize ?? desiredSize,
}
});
}
這樣就可以建立 NodeGroup 了。
最後我們需要產生 kubeconfig,這樣才能透過 kubectl 或是 k8s api 對 API Server 下指令。
產生 kubeconfig 的方法:
public getKubeconfig(): pulumi.Output<string> {
return pulumi.all([this.cluster.name, this.cluster.endpoint, this.cluster.certificateAuthority.data]).apply(([clusterName, endpoint, ca]) => {
return `
apiVersion: "v1",
clusters:
- cluster:
server: ${endpoint}
certificate-authority-data: ${ca}
name: "${clusterName}"
contexts:
- context:
cluster: "${clusterName}"
user: "aws"
name: "aws"
current-context: "aws"
kind: "Config"
users:
- name: "aws"
user:
exec:
apiVersion: "client.authentication.k8s.io/v1alpha1"
command: "aws-iam-authenticator"
args:
- eks
- get-token
- --cluster-name
- ${clusterName}
`;
});
}
這樣產生出來的 kubeconfig 內容,我們可以再透過程式語言內建的檔案操作 API 將資料寫入檔案。就不在此示範了。
建立完 EKS Cluter 後,下一篇文章就會來部署一些服務在 Cluster 中。