手把手教你玩转 Kubeflow on EKS(一)
本文为手把手教你玩转 Kubeflow On EKS 系列文章的第一篇。
本篇作者
贺杨
云原生社区机器学习SIG成员, 亚马逊云科技解决方案架构师,具备 17 年 IT 专业服务经验,工作中担任过研发、开发经理、解决方案架构师等多种角色。在加入亚马逊云科技前,拥有多年外企研发和售前架构经验,在传统企业架构和中间件解决方案有深入的理解和丰富的实践经验。
粟伟
云原生社区机器学习SIG成员, 云原生社区管委会成员, 亚马逊云科技解决方案架构师,开源项目爱好者,致力于云原生应用推广、落地。具有 15 年以上的信息技术行业专业经验,担任过高级软件工程师,系统架构师等职位,在加入亚马逊云科技之前曾就职于 Bea, Oracle, IBM 等公司。
1. 前言
伴随着人工智能时代的来临,越来越多的业务场景需要我们利用 AI 技术去支持,Gartner 在 2019 年发布的一份关于 AI 的预测报告中指出,在过去的一年里,采用 AI 的企业数量增加了两倍,而 AI 成为了企业 CIO 们考虑的头等大事。CIO 在企业内实施 AI 应用的过程里,必须考虑的五个要素中就有两项与 Kubernetes 相关:
•AI 将决定基础架构的选型和决策。在企业对 AI 的使用正在迅速增加的背景下,到 2023 年,人工智能将成为驱动基础架构决策的主要工作负载之一。加快 AI 的落地,需要特定的基础设施资源,这些资源可以与 AI 以及相关基础设施技术一起同步发展。我们认为,以 Kubernetes 强大的编排以及对 AI 模型的支持能力,通过在互联网厂商以及更多客户总结的最佳实践,Kubernetes 将成为企业内部 AI 应用首选的运行环境和平台。• 容器和 Serverless 将使机器学习模型作为独立的功能提供服务,从而以更低的开销运行 AI 应用。Gartner 直接指出了将容器作为机器学习模型的优势和趋势。
Amazon Elastic Kubernetes Service(Amazon EKS)是一项安全、可靠、可扩展的完全托管的 Kubernetes 服务,近期在 AWS 中国区域落地以来获得了用户的广泛关注。Amazon EKS 可让您在 AWS 上轻松运行 Kubernetes,无需您自行支持或维护 Kubernetes 控制层面,EKS 可跨多个 AWS 可用区来提供高可用特性,并自动将最新的安全补丁应用到您的集群控制平面,因此您可以更专注于应用程序的代码和功能,由于其安全性、可靠性和可扩展性,许多企业在 EKS 上 运行任务关键型应用程序。特别在近两年,有越来越多的公司用 kubernetes 来运行各种各样的工作负载,尤其是机器学习领域。各种 AI 公司或者互联网公司的 AI 部门都会尝试在 Amazon EKS 上运行 TensorFlow、PyTorch、MXNet 等等分布式学习的任务。使用 Amazon EKS 对机器学习的训练任务进行管理有如下好处:
• 有效利用资源 - Amazon EKS 能够跟踪不同工作节点的属性,例如存在的 CPU 或 GPU 的类型和数量,在将作业调度到节点时,Kubernetes 会根据这些属性,对资源进行有效分配。• 隐藏复杂性– 容器提供了一种独立于语言和框架的,有效打包机器学习工作负载的方式,从而屏蔽掉机器学习任务对底层技术栈的依赖。Kubernetes 则提供了一个可靠的工作负载编排和管理平台,Amazon EKS 通过必要的配置选项、API 和工具来管理这些工作负载,从而使工程师可以通过 yaml 文件,即可控制这些上层 ML 应用• 资源隔离 - 通过 Amazon EKS 的命名空间的功能,可以将单个物理 Kubernetes 集群划分为多个虚拟集群,使单个集群可以更轻松地支持不同的团队和项目,每个名称空间都可以配置有自己的资源配额和访问控制策略,满足复杂的多租户需求,从而能更充分地利用各种底层资源• 弹性伸缩 - 对于机器学习这种资源密集型工作负载,Amazon EKS 最适合于根据工作负载随时自动扩展或收缩计算规模,相对于虚拟机或物理机而言,通过容器完成扩展和收缩更为平稳、快速、简单• 存储持久化 -Amazon EKS 提供了将存储连接到容器化工作负载的基本机制,持久卷 PV 提供了 Kubernetes 对有状态应用程序(包括机器学习)的基本支持。
Amazon Elastic Kubernetes Service 自身强大的资源调度能力能够很好的帮助企业解决机器学习平台和资源的一致性,扩展性,移植性问题,然而部署和使用针对机器学习进行优化的 Kubernetes 平台,并支撑机器学习模型开发、构建、训练以及部署,却绝对不像说起来这么轻松,数据科学家有许多相同的关注点:可重复的实验(比如可重复的构建);可移植和可复制的环境(如在开发、过渡和生产环境中具有相同的设置);凭证管理;跟踪和监控生产环境中的指标;灵活的路由;轻松扩展。这为 Amazon EKS 上运行机器学习负载带来了很大的挑战。
而 Kubeflow 的出现很好解决了在 kubernetes 上运行机器学习负载面临的挑战,Kubeflow 是一个为 Kubernetes 构建的可组合,便携式,可扩展的标准的云原生机器学习平台。kubeflow 于 2017 年 12 月在 KubeCon 美国大会上宣布开源,并在过去两年中迎来了远超预期的迅猛发展。特别是 Kubeflow 的首个主要版本 1.0 版本的正式发布,kubeflow1.0 版本是一个里程碑,能够全面支撑起用户在机器学习开发、构建、训练与部署这个完整的使用过程。kubeflow 的目标是让 Kubernetes 做它擅长的事情,Kubeflow 致力于让 Kubernetes 上进行的机器学习任务组件化、可移植、可扩展,让机器学习 (ML) 模型的规模化和部署到生产尽可能简单,它的优势具体体现在以下几个方面:
• 在不同的基础设施上进行简单、可重复、可移植的部署 (例如,在本地进行试验,然后迁移到本地集群或云上)• 部署和管理松耦合的微服务,实现了 Cloud Native ML 的云原生,即本地训练好的模型,可以一键上云,使得本地开发和云开发在一个环境中,效率大大提高,机器学习(ML)工程师和数据科学家可以轻松地利用 aws 云资产(Amazon EKS)来处理 ML 工作负载• 简化了在 Kubernetes 上面运行机器学习任务的流程, 实现了一套完整可用的自动化流水线• 可扩展性好,能满足内部业务的定制化需求,自动调配计算资源,按需缩放
在强大的贡献者社区的支持下, 企业可以在任何符合 Kubernetes 的群集上使用 Kubeflow,Kubeflow 提供了一种在 Kubernetes 上运行机器学习工作负载的简单、可移植和可伸缩的方法,使机器学习 (ML) 工作流在 Kubernetes 上的部署变得简单、可移植和可伸缩。Kubeflow 可以帮助企业在软件开发和机器学习之间的通用基础架构上实现标准化,并在机器学习生命周期的每个步骤中利用开源数据科学和云原生生态系统。
在 kubeflow1.0 版本中,一组核心应用组件已经能够稳定运行,包括 Katib(超参数优化),KFServing(模型服务),Fairing(SDK),Kubeflow 管道,kfctl(控制平面),清单配置,TF-Operator 和 PyTorch-operator(模型训练),能够高效支持企业在 Kubernetes 上的模型开发、构建、训练以及部署。Kubeflow 的 1.0 版本将全面支撑起用户的开发、构建、训练与部署这个完整的使用过程。
Kubeflow 1.0 正式毕业的应用组件包括:
•Kubeflow 的 UI,即集中仪表板•Jupyter notebook 控制器与 Web 应用• 用于分布式训练的 Tensorflow Operator(TFJob)以及 PyTorch Operator• 用于部署以及升级的 kfctl• 用于多用户管理的配置文件控制器与 UI
如图所示,Kubeflow 1.0 允许用户使用 Jupyter 来开发模型,使用 Fairing 之类的 Kubeflow 工具(Kubeflow 的 python SDK)来构建容器,并创建 Kubernetes 资源来训练他们的模型,定义复杂的 ML 工作流的管道用于跟踪数据集,作业和模型的元数据,katib 用于超参数调整,最后使用 KFServing,在 Knative 来创建并部署服务器进行推理。
在本系列文章中,您将学习到:
• 实现在 Amazon EKS 中国区部署和创建 Kubeflow,在 Kubeflow 中创建并使用 Jupyter 笔记本,在笔记本中使用 TensorFlow 运行一个单节点培训和推理。• 实现从创建托管的 Jupyter 笔记本,用 kubeflow fairing 远程构建模型训练镜像,用 TFJob 实现分布式训练用于图像分类的 MNIST 机器学习模型,用 TensorFlow Serving 一键式模型部署以及应用界面集成进行在线预测的一个端到端机器学习的完整过程。• 实现通过 Kubeflow pipeline 集成 Amazon Sagemaker 实现端到端的机器学习过程,包括如何在 kubeflow notebook 笔记本中安装 Pipeline SDK,构建和编译 Kubeflow Pipeline,调用 SageMaker 超参数优化组件进行超参数优化,训练模型和创建模型,并在 Amazon SageMaker 中批量推理和部署模型端点。
2. 在 Amazon EKS 中国区安装和部署 Kubeflow
1)先决条件
首先,您需要设置 Amazon Elastic Kubernetes Service (Amazon EKS[1]) 集群。在本演示中,我们将使用 eksctl[2] 来启动集群。本文需要的软件环境有 aws cli , eksctl ,kubectl,e aws-iam-authenticator 以及 eks 对应操作的 IAM 权限。具体安装步骤请参考 2020_EKS_Launch_Workshop / 步骤 1 - 准备实验环境。安装完必备工具之后,启动 Amazon EKS 集群。在本例中,我们会将集群部署到 cn-northwest-1(即 AWS 中国宁夏区域)中。
本文选择了缺省的 kfctl 配置文件,以简化 kubeflow 安装。但是,我们建议在企业生产环境中安装 Cognito 配置并添加身份验证和 SSL (通过 ACM),有关启用 Cognito 所需的其他步骤,请参阅 Kubeflow documentation[3] 文档。
2) 设置环境变量
执行以下命令来设置环境变量,设置 Kubeflow 应用程序目录
export REGION=cn-northwest-1
export CLUSTER_NAME=kubeflow
export BASE_DIR=$(pwd)
export KF_NAME=${CLUSTER_NAME}
export KF_DIR=${BASE_DIR}/${KF_NAME}
export CONFIG_FILE=${KF_DIR}/kfctl_aws.yaml
3) 使用 eksctl 创建 EKS 集群
由于 Kubeflow 需要较多的计算节点资源来部署,通过执行以下操作创建一个 4 个工作节点 EKS 集群,创建过程大约需要十几分钟,请耐心等待。
eksctl create cluster --name=${CLUSTER_NAME} --nodes=4 --managed --alb-ingress-access --region=${REGION}
获取 EKS 工作节点 role,配置环境变量用于后续使用
export STACK_NAME=$(eksctl get nodegroup --cluster $CLUSTER_NAME --region $REGION -o json | jq -r '.[].StackName')
export NODE_INSTANCE_ROLE=$(aws cloudformation describe-stack-resources --region $REGION --stack-name $STACK_NAME | jq -r '.StackResources[] | select(.LogicalResourceId=="NodeInstanceRole") | .PhysicalResourceId' )
4) 安装 kubeflow
下载 kfctl 工具用于 kubeflow 部署和升级
curl --silent --location "https://github.com/kubeflow/kfctl/releases/download/v1.0.1/kfctl_v1.0.1-0-gf3edb9b_linux.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/kfctl /usr/local/bin
配置和下载kubeflow文件,本文中安装使用非cognito版本,默认不进行身份验证。(注意:如果存在文件不能下载的问题,可以尝试手工下载并上传到指定位置$CONFIG_URI)
export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_aws.v1.0.1.yaml"
export KF_NAME=${CLUSTER_NAME}
mkdir -p ${BASE_DIR}
export KF_DIR=${BASE_DIR}/${KF_NAME}
mkdir -p ${KF_DIR}
wget -O ${KF_DIR}/kfctl_aws.yaml $CONFIG_URI
export CONFIG_FILE=${KF_DIR}/kfctl_aws.yaml
替换 kfctl_aws.yaml 中的 region 和 role 为当前的创建 eks 的 region 和 node 节点使用的 role
sed -i'.bak' ${CONFIG_FILE}
sed -i -e "s/eksctl-kubeflow-aws-nodegroup-ng-a2-NodeInstanceRole-xxxxxxx/$NODE_INSTANCE_ROLE/g" ${CONFIG_FILE}
sed -i -e 's/us-west-2/'"$REGION"'/' ${CONFIG_FILE}
检查 kfctl_aws.yaml 是否正确替换
region: cn-northwest-1
roles:
- eksctl-kubeflow-example-nodegroup-ng-185-NodeInstanceRole-XXXXXX
kfclt 本质上是使用了 kustomize 来安装,kustomize 的设计目的是给 kubernetes 的用户提供一种可以重复使用同一套配置的声明式应用管理,可以通过 kfctl build 生成 kubeflow kustomize 配置文件
kfctl build -f ${CONFIG_FILE}
由于网络问题,海外 gcr.io, quay.io 的镜像可能无法下载,需要通过修改镜像的方式安装,把镜像 url 替换成 aws 国内镜像站点 url:
sed -i "s/gcr.io/048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn\/gcr/g" `grep "gcr.io" -rl ${KF_DIR}`
sed -i "s/quay.io/048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn\/quay/g" `grep "quay.io" -rl ${KF_DIR}`
运行 kfctl apply 开始在 EKS 上安装和部署 kubeflow
kfctl apply -V -f ${CONFIG_FILE}
安装 Kubeflow 及其工具集可能需要数分钟。有一些的 pod 最初可能会出现 Error 或 CrashLoopBackOff 状态。需要一些时间,它们会自动修复,并进入运行状态。
5) 配置 kubeflow dashboard
Kubeflow dashboard 通过在 istio 中的 ingress gateway 将服务暴露给外部使用,运行下列命令检查 ingress gateway 状态
kubectl get service istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway NodePort 10.100.239.93 <none> 15020:31062/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32662/TCP,15030:31314/TCP,15031:32088/TCP,15032:30973/TCP,15443:30713/TCP 27h
通过kubectl port-forward端口转发映射本地8080端口到指定的kubeflow dashboard 80端口
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80
6) 验证 kubeflow 是否成功部署
运行下面的命令检查状态,如果过一段时间后仍不正常,请通过查看日志进行故障排除。
kubectl -n kubeflow get all
kubeflow 提供多租户支持,用户无法在 Kubeflow 的默认名称空间中创建笔记本。
第一次访问 kubeflow 时,可以使用一个匿名命名空间。如果您想要创建不同的 Jupyter 用户空间,您可以创建配置文件,然后运行 kubectl apply -f Profile .yaml。kubeflow 配置文件控制器将创建新的名称空间和服务帐户,允许在该名称空间中创建笔记本。
apiVersion: kubeflow.org/v1beta1
kind: Profile
metadata:
name: aws-sample-user
spec:
owner:
kind: User
name: aws-sample-user
7) 访问 Kubeflow 用户界面
从本地网络浏览器输入 http://127.0.0.1:8080/,您就可以进入到 Kubeflow UI 界面,Kubeflow dashboard 默认为无身份验证。点击 dashboard 中 Start Setup,设置 namespace 的值为 eksworkshop
点击 Finish 浏览 kubeflow dashboard
8) 创建和使用 upter notebook
Jupyter 笔记本通常用于数据清洗和转换、数值模拟、统计建模、数据可视化、机器学习等。利用 Kubeflow,每位数据科学家乃至数据团队都将拥有自己的命名空间,在其中轻松运行工作负载。命名空间提供强大的安全保障与资源隔离机制。利用 Kubernetes 资源配额功能,平台管理员能够轻松限制个人或者团队用户的资源消耗上限,以保证资源调度的公平性。使用 Kubeflow 1.0,开发人员可以使用编程笔记本平台 Jupyter 和 Kubeflow 工具(例如 Kubeflow 的 Python 软件开发工具包)来开发模型,构建容器并创建 Kubernetes 资源来训练那些模型,在 Kubeflow dashboard 中通过点击 Create a new Notebook server 可以轻松创建一个 jupyter 笔记本的实例:
选择您在上一个部步骤中创建的 namespace :
为创建的 Jupyter 笔记本指定一个名称:
kubeflow 提供了 tensorflow 和 pytorch 的默认镜像,选择 tensorflow 默认的 Image 如下:
aws 已经默认提供如下的 docker 镜像:
048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr/tensorflow-1.15.2-notebook-cpu:1.0.0
048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr/tensorflow-1.15.2-notebook-gpu:1.0.0
048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr/tensorflow-2.1.0-notebook-cpu:1.0.0
048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr/tensorflow-2.1.0-notebook-gpu:1.0.0
为创建的 Jupyter 笔记本设置内存和 cpu 资源 ,设置 CPU 值为 1.0,Memory 为 1G
滚动到底部,接受所有其他默认设置,然后单击 LAUNCH,等待 Jupyter 笔记本启动,启动成功后,点击 CONNECT
在 Jupyter 笔记本界面里点击 New, 选择 Python3,创建一个新的 Python 3 环境的 Jupyter 笔记本
9) 训练模型
将实例代码粘贴到 notebook 中。这段 Python 样例代码会使用 TensorFlow 基于 MNIST 数据集训练模型,点击 Run 运行训练代码。
from __future__ import print_function
import tensorflow as tf
from tensorflow import keras
# Helper libraries
import numpy as np
import os
import subprocess
import argparse
# Reduce spam logs from s3 client
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
def preprocessing():
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
# scale the values to 0.0 to 1.0
train_images = train_images / 255.0
test_images = test_images / 255.0
# reshape for feeding into the model
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1)
test_images = test_images.reshape(test_images.shape[0], 28, 28, 1)
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
print('\ntrain_images.shape: {}, of {}'.format(train_images.shape, train_images.dtype))
print('test_images.shape: {}, of {}'.format(test_images.shape, test_images.dtype))
return train_images, train_labels, test_images, test_labels
def train(train_images, train_labels, epochs, model_summary_path):
if model_summary_path:
logdir=model_summary_path # + datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)
model = keras.Sequential([
keras.layers.Conv2D(input_shape=(28,28,1), filters=8, kernel_size=3,
strides=2, activation='relu', name='Conv1'),
keras.layers.Flatten(),
keras.layers.Dense(10, activation=tf.nn.softmax, name='Softmax')
])
model.summary()
model.compile(optimizer=tf.train.AdamOptimizer(),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
if model_summary_path:
model.fit(train_images, train_labels, epochs=epochs, callbacks=[tensorboard_callback])
else:
model.fit(train_images, train_labels, epochs=epochs)
return model
def eval(model, test_images, test_labels):
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('\nTest accuracy: {}'.format(test_acc))
def export_model(model, model_export_path):
version = 1
export_path = os.path.join(model_export_path, str(version))
tf.saved_model.simple_save(
keras.backend.get_session(),
export_path,
inputs={'input_image': model.input},
outputs={t.name:t for t in model.outputs})
print('\nSaved model: {}'.format(export_path))
def main(argv=None):
parser = argparse.ArgumentParser(description='Fashion MNIST Tensorflow Example')
parser.add_argument('--model_export_path', type=str, help='Model export path')
parser.add_argument('--model_summary_path', type=str, help='Model summry files for Tensorboard visualization')
parser.add_argument('--epochs', type=int, default=5, help='Training epochs')
args = parser.parse_args(args=[])
train_images, train_labels, test_images, test_labels = preprocessing()
model = train(train_images, train_labels, args.epochs, args.model_summary_path)
eval(model, test_images, test_labels)
if args.model_export_path:
export_model(model, args.model_export_path)
运行后会创建一个新的代码单元格,在这个新单元格中输入 main (),然后单击 Run
上面是输出结果,输出的前几行显示下载了 mnist 数据集,下载的训练数据集是 60000 个图像,测试数据集为 10000 个图像,并给出了用于训练的超参数,五次 Epoch 的输出,最后在训练完成后输出了模型的损失值和准确率 (Accuracy)。
3. 小结
Amazon EKS 是一个完全托管的 Kubernetes 服务,该服务自身强大的资源调度能力能够很好的帮助企业解决机器学习平台和资源的一致性,扩展性,移植性问题,而 Kubeflow 是在 Kubernetes 上运行 TensorFlow、JupyterHub、Seldon 和 PyTorch 等框架的一种很好的方式,Kubeflow 很好解决了在 kubernetes 上运行机器学习负载面临的挑战,全面支撑起用户在机器学习开发、构建、训练与部署这个完整的使用过程。在本文中实现了在 Amazon EKS 中国区部署和创建 Kubeflow 1.0,在 Kubeflow 中创建并使用 Jupyter 笔记本,并在笔记本中使用 TensorFlow 在 Kubeflow 中运行一个简单的模型训练。
原文链接
[1]
亚马逊云科技官方博客: https://aws.amazon.com/cn/blogs/china/teach-you-how-to-handle-kubeflow-on-eks-1/
引用链接
[1]
Amazon EKS: https://aws.amazon.com/eks/[2]
eksctl: https://eksctl.io/[3]
Kubeflow documentation: https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/
关于云原生社区
云原生社区成立于 2020 年 5 月 12 日,作为中立的云原生终端用户社区,致力于推广云原生技术,构建开发者生态。点击了解我们。
云原生社区基于成员兴趣创建了多个 SIG(特别兴趣小组),如 Kubernetes、Istio、Envoy、Dapr、OAM、边缘计算、机器学习、可观察性等。请扫描下面的二维码,点击公众号后台的「加入我们」,填写问卷加入社区。
点击下方“阅读原文”查看更多↓↓↓