亚马逊AWS官方博客

OpenSource | 使用 virtual-kubelet 运行 AWS Fargate

AWS Fargate 是一项全新的技术。有了它,您无需预配置、管理或扩展服务器即可运行容器。现在,Fargate 与 Amazon Elastic Container Service (ECS) 直接实现了集成。自从我们在 re:Invent 2017 大会上发布 Fargate 后,许多客户向我们反映,他们对使用 Fargate 运行 Kubernetes 非常感兴趣。为了帮助实现这一点,我们已经开始探究使用 virtual-kubelet 连接 Fargate 和 Kubernetes。virtual-kubelet 是一个开源的社区主导型项目,它允许使用任意计算资源支持 Kubernetes 工作程序节点。我们已经编写了一个新的 provider 插件,它支持使用 virtual-kubelet 创建 Fargate 任务,并已将该插件并入 virtual-kubelet 上游项目。这款新插件是只是在将 AWS Fargate 托管的数据层面扩展到 Kubernetes 方面迈出的探索性的一步,在它可以在所有使用案例中无缝运行之前,我们还有许多工作要做。现在,您不妨自行尝试以下几个简单的步骤:

步骤 1:使用 kops 创建一个单主节点的 Kubernetes 集群

我们将创建一个简单的测试环境来展示由 AWS Fargate 支持的 Kubernetes 工作负载。

virtual-kubelet 和 Fargate

第一步是安装一个 kops 集群。在安装 kops 时,我们使用具有两个 EC2 工作程序节点和一个 virtual-kubelet 实例的混合环境。virtual-kubelet 和 Fargate 上不支持的任意 Kubernetes 工作负载都可以照常在两个工作程序节点上轻松安排。按照以下说明使用此存储库:github.com/kubernetes/kops/blob/master/docs/aws.md。阅读关于使用 kops 在 AWS 上管理 Kubernetes 集群的博文,也可能会有所帮助。

$ export KUBERNETES_VERSION=https://storage.googleapis.com/kubernetes-release/release/v1.9.0/
$ export AWS_AVAILABILITY_ZONES=us-east-1
$ export CLUSTER_NAME=dnishi-kops1.k8s.local

$ kops create cluster —name $CLUSTER_NAME —zones $AWS_AVAILABILITY_ZONES —kubernetes-version $KUBERNETES_VERSION --yes

##Tested with Kubernetes v1.8.0+
##Kops 1.6.2+ can be easily created as a gossip-based cluster and the cluster name has to end with k8s.local

完成 kops 安装后,验证您的节点是否正在使用 kubectl 运行:

$ kubectl get nodes
NAME                            STATUS    ROLES     AGE       VERSION
ip-172-20-42-7.ec2.internal     Ready     master    5h        v1.9.0
ip-172-20-44-230.ec2.internal   Ready     node      5h        v1.9.0
ip-172-20-58-31.ec2.internal    Ready     node      5h        v1.9.0

复制 kops 集群的 kubeconfig 文件并保存。在即将运行 virtual-kubelet 的 EC2 实例上需要使用此文件。

步骤 2:从上游存储库构建 virtual-kubelet

在构建之前,请先确保已安装 Go。首次使用的用户请按照以下方法设置变量:

$ export GOPATH=$HOME/go

我们将 github.com/virtual-kubelet 用作基础路径。

$ mkdir -p $GOPATH/src/github.com/virtual-kubelet
$ cd $GOPATH/src/github.com/virtual-kubelet

如果您是首次克隆此存储库,请使用以下命令。如果您之前克隆过 virtual-kublet,请将以下命令中的“git clone”替换为“git pull”。

$ git clone https://github.com/virtual-kubelet/virtual-kubelet
$ cd virtual-kubelet
$ make build

将所有依赖项都添加到存储库中,并与 virtual-kubelet 一起构建。二进制文件位于 virtual-kubelet/bin 目录中。

步骤 3:创建 Fargate 任务

如果您之前未使用过 AWS Fargate,最简单的入门方法就是体验 Fargate 的首次运行。这样会在您的 AWS 账户中对 Fargate 采用默认设置。它将创建一个默认的 Fargate 集群*、IAM 角色,以及一个具有 Internet 网关和默认安全组的默认 VPC。在第一次运行之后,对个别设置进行微调会比较容易。在 Fargate 上运行首个应用程序后,请访问 AWS ECS 控制台,仔细查看您的 Fargate 资源。记录示例应用程序的子网和安全组。*由于 Fargate 会将服务器抽离出来,因此该集群仅作为一个逻辑构造,对正在运行的容器进行分组。

步骤 4:创建一个 EC2 实例,以使用 Fargate provider 插件运行 virtual-kubelet

为 EC2 实例创建一个 IAM 角色。许多 AWS 服务要求您利用角色控制服务可以访问的内容。如果按 IAM 角色适用的特定目的进行分类,可分为 EC2 实例的服务角色(举例),或服务相关角色。运行 virtual-kubelet 的 EC2 实例需要对 ECS API 拥有完全访问权限。按照以下步骤创建适当的 IAM 角色:使用 AWS 控制台:

  1. 在 AWS 控制台上选择 us-east-1 区域中的 IAM 角色
  2. 创建角色,选择 AWS服务,选择“EC2”作为将使用该角色的服务,然后单击“Next: Permissions”(下一步:权限)。
  3. 搜索并选择“AmazonECS_FullAccess”,然后单击“Next: Review”(下一步:查看)。
  4. 将角色命名为“VK-ECSFullAccess”,完成操作。您会在“IAM 角色”页面上看到该新角色。

使用 aws-cli:创建角色,然后附加信任策略,以支持 EC2 承担此角色:

$ aws iam create-role --role-name VK-ECSFullAccess --assume-role-policy-document file://VK-Role-Trust-Policy.json

以下是 VK-Role-Trust-Policy.json

$ cat VK-Role-Trust-Policy.json
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Principal": {"Service": "ec2.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }
}

调用 attach-role-policy 命令,向此 IAM 角色授予权限,以访问您帐户中的资源:

$ aws iam attach-role-policy --role-name VK-ECSFullAccess --policy-arn arn:aws:iam::aws:policy/AmazonECS_FullAccess

创建 EC2 所需的实例配置文件以包含该角色:

$ aws iam create-instance-profile --instance-profile-name EC2-AmazonECS_FullAccess

最后,将角色添加到实例配置文件:

$ aws iam add-role-to-instance-profile --instance-profile-name EC2-AmazonECS_FullAccess --role-name VK-ECSFullAccess

创建 EC2 实例并将新角色附加到其中:

  • 使用 EC2 控制台,在其他 kops 工作程序节点所在的同一 VPC 和子网中创建一个 EC2 节点,并在创建过程中将 VK-ECSFullAccess-Role 添加到 EC2 节点。
  • 或者,使用以下 aws-cli 命令:

在其他 kops 工作程序节点所在的同一子网和安全组中创建一个 ec2 Debian GNU/Linux 8 (Jessie) 实例:

$ aws ec2 run-instances --image-id ami-b14ba7a7 --count 1 --instance-type t2.micro --key-name ${MyKeyPair-xxxxx} --security-group-ids ${sg-xxxxxxxx} --subnet-id ${subnet-xxxxxxxx} --associate-public-ip-address

调用 associate-iam-instance-profile 命令,将新创建的 IAM 角色 YourNewRole 的实例配置文件 YourNewRole-Instance-Profile 附加到 EC2 实例 YourInstanceId 中:

$ aws ec2 associate-iam-instance-profile --instance-id ${i-xxxxxxxxxxxxx} --iam-instance-profile Name=EC2-AmazonECS_FullAccess

调用 describe-iam-instance-profile-association 命令,验证现在是否已将 IAM 角色附加到该实例:

$ aws ec2 describe-iam-instance-profile-associations

将以下文件复制到新的 EC2 节点:

  • “virtual-kubelet”二进制文件
  • “fargate.toml”配置文件。将 fargate.toml 文件更新为步骤 3中的子网值、安全组值。此外,如果您需要从外部访问映像,请更改 AssignPublicIPv4Address = true。
  • kops 集群中的“kubeconfig”文件。将此文件移动到 /root/.kube/config 路径
$ scp -r -i ${path-to-MyKeyPair-xxxxx} ${path-to-virtual-kubelet/providers/aws/fargate.toml} ~/.kube/config admin@ec2.xx-xxx-xxx-xx.compute-1.amazonaws.com
$ ssh -i ${path-to-MyKeyPair-xxxxx} admin@ec2.xx-xxx-xxx-xx.compute-1.amazonaws.com
$ sudo -i
$ mv config /root/.kube/config

运行 virtual-kubelet 并保持运行状态:

$ ./virtual-kubelet --provider aws --provider-config fargate.toml

步骤 5:通过您的 kubectl 客户端确认集群已准备就绪

启动 virtual-kubelet 进程后,您会看到它在集群上注册为代理。

$ kubectl get nodes
NAME                            STATUS    ROLES     AGE       VERSION
ip-172-20-42-7.ec2.internal     Ready     master    1d        v1.9.0
ip-172-20-44-230.ec2.internal   Ready     node      1d        v1.9.0
ip-172-20-58-31.ec2.internal    Ready     node      1d        v1.9.0
virtual-kubelet                 Ready     agent     14s       v1.8.3

步骤 6:创建 Kubernetes 对象(pod、部署、副本集、服务)

使用文本编辑器部署带有三个副本的 nginx,以创建一个包含以下内容的 YAML 文件并运行它。要在 Fargate (virtual-kubelet) 上分配 pod,我们使用清单中的 nodeSelector 约束,这是 PodSpec的一个字段。它指定了键值对的映射。此外,您还可以使用 Kubernetes taint 来模拟这一行为。nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "1000Mi"
            cpu: "500m"
      nodeSelector:
        type: virtual-kubelet

现在,部署您创建的 YAML 文件:

$ kubectl create -f nginx-deployment.yaml
deployment.apps "nginx-deployment" created
$ kubectl get deployments -o wide
NAME              DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE  CONTAINERS  IMAGES       SELECTOR
nginx-deployment     3       3         3             0     12s  nginx       nginx:1.7.9 app=nginx

$ kubectl get pods -o wide
NAME                               READY      STATUS      RESTARTS     AGE     IP          NODE
nginx-deployment-6b488d64b-47hvk   1/1        Running     0            2m      10.0.1.23   virtual-kubelet
nginx-deployment-6b488d64b-dj45s   1/1        Running     0            2m      10.0.1.161  virtual-kubelet
nginx-deployment-6b488d64b-p6vsb   1/1        Running     0            2m      10.0.1.95   virtual-kubelet

请注意,粗体的 nginx pod 元数据已经作为任务定义显示在下面的 Fargate 控制面板中。

让我们将 Fargate 上运行的 nginx-deployment 从 v1.7.9 更新为 v1.9.1:

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

deployment.apps "nginx-deployment" image updated

$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 1 old replicas are pending termination...
Waiting for rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

Fargate 任务同样会一次更新一项任务。如果您单击一项任务,您会看到映像版本已经从 v1.7.9 更新为 v1.9.1。几秒钟之内,每项任务都会更新到 v1.9.1,而且每次会对一项任务重复一次该进程。


使用单个命令部署 20 个 pod。使用 nginx-deployment-new.yaml。如 Fargate 控制面板所示,这些任务可以在几秒钟内完成:

$ kubectl create -f nginx-deployment-new.yaml
deployment.apps "nginx-deployment" created

$ kubectl get deployments -o wide
NAME              DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE  CONTAINERS  IMAGES      SELECTOR
nginx-deployment    20       20       20           0       14s    nginx  nginx:1.7.9   app=nginx

总结观点

现在,virtual-kubelet provider 插件无法支持所有 Kubernetes 使用案例和应用程序模式。我们希望可以在计算方面为 Kubernetes 用户提供新的途径,而现在我们已经迈出了第一步。我们很高兴能与社区合作,共同讨论如何最好地实现 Kubernetes 的无节点设计概念。我们希望您能加入我们,提出建议、贡献代码,并使用您的应用程序帮助我们测试该插件。您可以:

AWS 将参加 2018 年 5 月 2 日至 4 日在丹麦哥本哈根举行的 KubeCon EU 大会在此次大会上,我们将展示这一插件。此外,我们还会展示即将推出的托管型 Kubernetes 服务 Amazon Elastic Container Service for Kubernetes (Amazon EKS)。


注意:本博文是专门针对中级用户编写的。需掌握 Linux、Go、Docker 和 K8s 相关知识。此外,virtual-kubelet 目前还不是稳定的代码库,如果出现崩溃,属于正常现象。希望您能够为我们提供帮助,使之更稳定。


Nishi DavidsonNishi Davidson 在云计算基础架构和软件应用程序领域有着长达 15 年的工作经验,在东南亚和美国市场负责过相关领域的工程、产品管理和战略工作。目前,她在 AWS 主持 Kubernetes 社区的开源工程设计。之前,她曾负责 SAP 的私有云、内部 BU 的 Kubernetes 托管服务工程等工作。在 HP、TCS、Juniper Networks、NetApp 和 DSSD (EMC) 工作期间,Nishi 负责领导产品/现场工程团队,向市场推出了多款云产品/解决方案。Nishi 拥有麻省理工学院斯隆商学院的工商管理硕士学位和安那大学 Guindy 工程学院的电气与电子工程学士学位。