Amazon EKS+Kubeflow+Karpenter 助力构建弹性机器学习平台

机器学习
亚马逊云科技
0
0
{"value":"#### **前言**\n\n\n\n随着[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)的不断发展和在各个行业的使用,很多企业已经从最初关注构建模型、算法选择到了现在如何构建自己的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台,在该平台上实现从数据处理、模型训练、模型部署和 CI/CD。现在[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台有很多,比较受欢迎的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台有亚马逊云科技的托管服务 SageMaker 和开源的 Kubeflow, MLflow 等。本文结合用户的场景,使用 Kubeflow 构建一个弹性可灵活扩展的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台。\n\n\n\nKubeflow ([https://www.kubeflow.org](https://www.kubeflow.org)) 是 Kubernetes 的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)工具包,目标是利用 Kubernetes 的优点,尽可能简单地扩展[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail) (ML) 模型并将它们部署到生产环境。在 Kubernetes 部署选择上,我们根据用户的使用情况选择了 [Amazon Elastic Kubernetes Service](https://aws.amazon.com/cn/eks/?trk=cndc-detail)\n([https://aws.amazon.com/cn/eks/?nc1=h_ls](https://aws.amazon.com/cn/eks/?nc1=h_ls)) ([Amazon EKS](https://aws.amazon.com/cn/eks/?trk=cndc-detail)) ,它是一项托管容器服务,可以在云中和本地运行和扩展 Kubernetes 应用程序。最后我们会选择三剑客中的第三项,Karpenter, Karpenter ([https://karpenter.sh](https://karpenter.sh)) 是使用亚马逊云科技构建的开源、灵活、高性能的 Kubernetes 集群自动扩缩程序。它通过快速启动适当规模的计算资源来响应不断变化的应用程序负载,从而帮助提高应用程序可用性和集群效率。Karpenter 特别适合该用户在[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)中对于成本优化的需求,在无需配置任何 GPU 节点组情况下,快速的获得 GPU 资源进行模型训练和在训练结束后快速释放 GPU 资源。本方案中,我们会专注于使用这三个服务,构建弹性的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台。\n\n\n\n本方案部署在北京区域进行,本文通过四个部分总结如何在中国区搭建 Kubeflow 1.5.1并利用 Karpenter 进行动态的 GPU 资源的扩展满足 Kubeflow ML 训练的需求。\n\n\n\n- 准备环境\n- 部署 Kubeflow\n- 验证 Kubeflow 的安装,包含实验\n- 利用 Karpenter 进行动态的资源扩展满足 Kubeflow ML 训练的需求\n\n\n\n需要的服务和架构如下图:\n\n\n![image.png](1)\n\n\n#### **准备环境**\n\n准备环境主要分为四部分:\n\n\n\n- 安装必要的工具\n- 创建 EKS 集群\n- 下载源码\n- 配置 image 拉取工具\n\n\n\n##### **安装必要的工具**\n\n\n\n在正式安装 Kubeflow 前,需要准备一些必要的工具,具体也可参考 Kubeflow on EKS \n([https://awslabs.github.io/kubeflow-manifests/docs/deployment/prerequisites/](https://awslabs.github.io/kubeflow-manifests/docs/deployment/prerequisites/)) 官网。安装时请一定注意工具版本,Python 3.8 和 Kustomize 3.2.0。\n\n\n\n- Amazon CLI\n([https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html))\n\n- eksctl ([https://eksctl.io/introduction/#installation](https://eksctl.io/introduction/#installation))\n\n- kubectl ([https://kubernetes.io/docs/tasks/tools](https://kubernetes.io/docs/tasks/tools)\n- yq ([https://mikefarah.gitbook.io/yq](https://mikefarah.gitbook.io/yq))\n\n- jq ([https://stedolan.github.io/jq/download/](https://stedolan.github.io/jq/download/))\n\n- kustomize version 3.2.0 ([https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.2.0](https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.2.0))\n\n- python 3.8+ ([https://www.python.org/downloads/](https://www.python.org/downloads/))\n\n- pip ([https://pip.pypa.io/en/stable/installation/](https://pip.pypa.io/en/stable/installation/))\n\n\n\n##### **创建 EKS 集群**\n\n\n\n创建一个新的集群为Kubeflow使用,关于EKS的版本选择,可以参考 [Amazon EKS](https://aws.amazon.com/cn/eks/?trk=cndc-detail) 和 Kubeflow 兼容性 ([https://awslabs.github.io/kubeflow-manifests/docs/about/eks-compatibility/](https://awslabs.github.io/kubeflow-manifests/docs/about/eks-compatibility/)) 网站。\n\n\n\n首先设置环境变量,EKS 集群名称和指定北京 Region。\n\n```\\nexport CLUSTER_NAME=kubeflow151\\nexport CLUSTER_REGION=cn-north-1\\n```\n\n\n\n创建集群:\n\n```\\neksctl create cluster --name \${CLUSTER_NAME} --version 1.21 --region \${CLUSTER_REGION} --nodegroup-name kf --node-type m5.xlarge --nodes 4 --nodes-min 4 --nodes-max 8 --managed --with-oidc\\n```\n\n\n\n下载源码\n\n\n\n此次实验基于1.5.1 进行,下载1.5.1相关的源码:\n\n```\\nexport KUBEFLOW_RELEASE_VERSION=v1.5.1\\nexport AWS_RELEASE_VERSION=v1.5.1-aws-b1.0.0\\ngit clone https://github.com/awslabs/kubeflow-manifests.git && cd kubeflow-manifests\\ngit checkout \${AWS_RELEASE_VERSION}\\ngit clone --branch \${KUBEFLOW_RELEASE_VERSION} https://github.com/kubeflow/manifests.git upstream\\n```\n\n\n\n##### **配置 image 拉取工具**\n\n\n\n在安装 Kubeflow 的时候,比较困难的一个问题是 image 的拉取,例如 k8s.gcr.io ([https://k8s.gcr.io](https://k8s.gcr.io)), gcr.io ([http://gcr.io](http://gcr.io)), quay.io ([https://quay.io](https://quay.io)) 等源的 image 拉取。关于这部分,我们在 [Amazon API Gateway](https://aws.amazon.com/cn/api-gateway/?trk=cndc-detail) Mutating Webhook For K8S ([https://github.com/aws-samples/amazon-api-gateway-mutating-webhook-for-k8](https://github.com/aws-samples/amazon-api-gateway-mutating-webhook-for-k8)) 基础上做了一些修改,具体可以参考自动化拉取 image \n([https://github.com/walkingerica/automate-pulling-and-mutating-webhook-for-k8](https://github.com/walkingerica/automate-pulling-and-mutating-webhook-for-k8)),概括来说,原理是在需要 gcr.io 等镜像的时候,该工具自动通过 Amazon Global 区域的 CodeBuild 拉取镜像并添加到中国区的 ECR 中。\n\n\n#### **部署 KubeFlow**\n\n在部署 KubeFlow on EKS 的时候有多种选择,除了原始安装方法外,Amazon 发行了Kubeflow on EKS 开源版本,允许客户使用现成的 Amazon 服务集成构建[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)系统并提供安装文档, 包括 RDS 和 S3 安装方法,Cognito, RDS 和 S3 安装方法等。本篇是使用的 RDS 和S3 安装方法。此部署方法用到的服务包含:\n\n\n\n- RDS:代替 KFP 和 Katib 使用的 MySQL pod,用于持久化 KFP 数据(例如实验、pipelines、job 信息等)和 Katib 日志信息。\n- S3:代替 MinIO 存储对象, 例如一些日志文件。\n- Secret Manager:存储 RDS 相关信息,像用户名密码和 Endpoint 等。\n\n\n\n##### **准备工作**\n\n\n\n因为代码中没有考虑对中国区的支持,需要手动修改一些代码。\n\n\n\n在 auto-rds-s3-setup.py 文件中需要修改两处:\n\n\n\n- iam_policies 部分,需要把 aws 替换成 aws-cn\n- s3_params 部分,需要把 amazonaws.com \n- ([http://s3.amazonaws.com.cn](http://s3.amazonaws.com.cn)) 换成 s3.amazonaws.com.cn ([http://s3.amazonaws.com.cn](http://s3.amazonaws.com.cn))\n\n\n\n```\\ndef create_secrets_iam_service_account():\\n print(\\"Creating secrets IAM service account...\\")\\n iam_policies = [\\n \\"arn:aws-cn:iam::aws:policy/AmazonSSMReadOnlyAccess\\",\\n \\"arn:aws-cn:iam::aws:policy/SecretsManagerReadWrite\\",\\n ]\\n\\n create_iam_service_account(\\n service_account_name=\\"kubeflow-secrets-manager-sa\\",\\n namespace=\\"kubeflow\\",\\n cluster_name=CLUSTER_NAME,\\n region=CLUSTER_REGION,\\n iam_policy_arns=iam_policies,\\n )\\n\\n print(\\"Secrets IAM service account created!\\")\\n\\n\\ndef setup_kubeflow_pipeline():\\n print(\\"Setting up Kubeflow Pipeline...\\")\\n\\n print(\\"Retrieving DB instance info...\\")\\n db_instance_info = get_db_instance_info()\\n\\n pipeline_rds_params_env_file = \\"../../awsconfigs/apps/pipeline/rds/params.env\\"\\n pipeline_rds_secret_provider_class_file = (\\n \\"../../awsconfigs/common/aws-secrets-manager/rds/secret-provider.yaml\\"\\n )\\n\\n rds_params = {\\n \\"dbHost\\": db_instance_info[\\"Endpoint\\"][\\"Address\\"],\\n \\"mlmdDb\\": \\"metadb\\",\\n }\\n edit_pipeline_params_env_file(rds_params, pipeline_rds_params_env_file)\\n\\n update_secret_provider_class(\\n pipeline_rds_secret_provider_class_file, RDS_SECRET_NAME\\n )\\n\\n pipeline_s3_params_env_file = \\"../../awsconfigs/apps/pipeline/s3/params.env\\"\\n pipeline_s3_secret_provider_class_file = (\\n \\"../../awsconfigs/common/aws-secrets-manager/s3/secret-provider.yaml\\"\\n )\\n\\n s3_params = {\\n \\"bucketName\\": S3_BUCKET_NAME,\\n \\"minioServiceRegion\\": CLUSTER_REGION,\\n \\"minioServiceHost\\": \\"s3.amazonaws.com.cn\\",\\n }\\n\\n```\n\n在 config 文件中 s3 endpoint 需要修改:\n\n```\\n{\\nartifactRepository:\\n{\\n s3: {\\n bucket: \$(kfp-artifact-bucket-name),\\n keyPrefix: artifacts,\\n endpoint: s3.cn-north-1.amazonaws.com.cn,\\n insecure: true,\\n accessKeySecret: {\\n name: mlpipeline-minio-artifact,\\n key: accesskey\\n },\\n secretKeySecret: {\\n name: mlpipeline-minio-artifact,\\n key: secretkey\\n }\\n },\\n archiveLogs: true\\n}\\n}\\n```\n\n\n\n##### **准备 RDS, S3 和 Secret Manager 环境**\n\n\n\n1. 首先确保从代码的根目录开始。\n\n```\\nexport REPO_ROOT=\$(pwd)\\n```\n\n\n\n2. 进入 tests/e2e 目录并安装依赖。\n\n```\\ncd tests/e2e\\npip install -r requirements.txt\\n```\n\n\n\n3. 准备需要使用的环境变量。\n\n```\\nexport CLUSTER_REGION=cn-north-1\\nexport CLUSTER_NAME=kubeflow151\\nexport S3_BUCKET=<YOUR S3 BUCKET>\\nexport MINIO_AWS_ACCESS_KEY_ID=<YOUR ACCESS KEY>\\nexport MINIO_AWS_SECRET_ACCESS_KEY=<YOUR SECRET ACCESS KEY>\\n```\n\n\n4. 配置 RDS, S3 和 Secret Manager 环境,安装 auto-rds-s3-setup.py。此步骤包含:\n\n\n\n- RDS 数据库创建\n- S3 桶创建\n- Secret Manager 设置\n- Serviceaccounts 创建\n- Secret Store CSI driver 设置等\n\n```\\nPYTHONPATH=.. python utils/rds-s3/auto-rds-s3-setup.py --region \$CLUSTER_REGION --cluster \$CLUSTER_NAME --bucket \$S3_BUCKET --s3_aws_access_key_id \$MINIO_AWS_ACCESS_KEY_ID --s3_aws_secret_access_key \$MINIO_AWS_SECRET_ACCESS_KEY\\n```\n\n![image.png](2)\n\n![image.png](3)\n\nPython 脚本执行后,会看到上面的 log 输出,为了确保安装过程成功,可以分别查看 pod 运行的状态、serviceaccounts 和 CSI driver 等。\n\n```\\nkubectl get pods —all-namespaces\\n```\n\n\n![image.png](4)\n\n```\\nkubectl describe serviceaccounts kubeflow-secrets-manager-sa -n kubeflow;\\n```\n\n![image.png](5)\n\n\n```\\nkubectl get csidriver\\n```\n![image.png](6)\n\n##### **Kubeflow 安装**\n\n\n\n执行如下命令安装,安装后也可以建议查看 pod 状态。\n\n```\\ncd \$REPO_ROOT \\nwhile ! kustomize build deployments/rds-s3 | kubectl apply -f -; do echo \\"Retrying to apply resources\\"; sleep 30; done\\n\\nkubectl get pods --all-namespaces \\n```\n\n\n\n如果各个 Pod 运行没有问题的话,执行如下命令后,就可通过 http://localhost:8080 访问 Kubeflow Dashboard, 默认用户名为 user@example.com,密码为12341234。因为涉及到 RDS 和 S3 的使用,请参考下一步验证安全结果。\n\n```\\nkubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80\\n```\n\n![image.png](7)\n\n\n登陆后,可以看到 Kubeflow 的控制台界面如下。Kubeflow 支持的主要功能可以在界面上找到,用户编程测试工作台 (Jupyter Notebook),超参调优 (Experiment(AutoML)), [机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)工作流(Pipeline)等。\n\n![image.png](8)\n\n#### **验证安装结果**\n\n\n\n在 Kubeflow 安装之后,我们通过两个方面进行验证,RDS 和 S3 的验证,这两个角度的验证也是在侧面验证超参调优和工作流工作。\n\n\n\n##### **验证 RDS数据库**\n\n\n\nRDS 中会存储\n\n1. 连接 RDS 数据库。\n\n```\\nkubectl run -it —rm —image=mysql:5.7 —restart=Never mysql-client — mysql -h <YOUR RDS ENDPOINT> -u <YOUR LOGIN> -p<YOUR PASSWORD>\\n```\n\n\n2. 连接成功后,查看 kubeflow 和mlpipeline 数据是否存在, 同时查看在mlpipeline中是否有如下的表。\n\n```\\nshow databases;\\nuse mlpipeline; show tables;\\n```\n\n![image.png](9)\n\n3. 登录进入到 Kubeflow Dashboard,使用此 yaml\n([https://github.com/awslabs/kubeflow-manifests/blob/main/tests/e2e/resources/custom-resource-templates/katib-experiment-random.yaml](https://github.com/awslabs/kubeflow-manifests/blob/main/tests/e2e/resources/custom-resource-templates/katib-experiment-random.yaml)) 文件(注意需要更改 namespace) 运行一个实验。具体操作为 Dashboard –> Experiments (AutoML) –> New Experiment。\n\n![image.png](10)\n\n实验成功后,RDS 中表中会有相关的实验执行信息。\n\n![image.png](11)\n\n##### **验证 S3**\n\n\n\n在 Kubeflow Dashboard 中,创建一个 Experiment 并运行,运行结束之后,我们可以去到第二步部署的 S3 bucket 中,如果可以查看到 log, S3 部分没有问题。可以参考下图:\n\n![image.png](12)\n\n![image.png](13)\n\n\n\n#### **利用 Karpenter 进行动态的资源扩展满足 Kubeflow ML 训练的需求**\n\n\n\n在 Karpenter 之前,EKS 用户使用 Cluster Autoscaler 动态调整集群的计算容量,他的原理是使用 [Amazon EC2 Auto Scaling ](https://aws.amazon.com/cn/ec2/autoscaling/?trk=cndc-detail)组\n\n(https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html)进行扩展底层的 EC2 资源。Karpenter 会观察未调度的一组容器 (pod) 的总资源请求,然后向 [Amazon EC2 ](https://aws.amazon.com/cn/ec2/?trk=cndc-detail)直接发送命令并作出启动和终止新节点的决策,从而减少调度延迟并降低基础设施成本。在[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)场景下,用户可以像该文中一样使用一个 EKS 节点组安装和管理 Kubeflow,在提交训练任务时,通过 Karpenter 开启 GPU 资源,在训练结束后终止 GPU 资源。\n\n\n\nKarpenter 的安装不在此介绍了,可以参考官方文档安装 ([https://karpenter.sh/v0.5.5/getting-started/](https://karpenter.sh/v0.5.5/getting-started/))。我们主要演示在 Karpenter 部署后,Kubeflow 中如何使用。使用验证 RDS 的例子,在 spec 中添加 resource 为 nvidia.com/gpu ([https://www.nvidia.com/gpu/](https://www.nvidia.com/gpu/)), 添加后在 Kubeflow Dashboard 中 Experiments (AutoML) 部分运行修改后的 yaml 文件。\n\n```\\n.......\\n trialSpec:\\n apiVersion: batch/v1\\n kind: Job\\n spec:\\n template:\\n metadata:\\n annotations:\\n sidecar.istio.io/inject: 'false'\\n spec:\\n containers:\\n - name: training-container\\n image: docker.io/kubeflowkatib/mxnet-mnist:v1beta1-45c5727\\n command:\\n - \\"python3\\"\\n - \\"/opt/mxnet-mnist/mnist.py\\"\\n - \\"--batch-size=64\\"\\n - \\"--lr=\${trialParameters.learningRate}\\"\\n - \\"--num-layers=\${trialParameters.numberLayers}\\"\\n - \\"--optimizer=\${trialParameters.optimizer}\\"\\n resources:\\n limits:\\n nvidia.com/gpu: 1\\n restartPolicy: Never\\n```\n\n\n\n\n\n在提交了这个 Experiment 后,可以通过命令行查看 Karpenter 的日志。我们可以看到 GPU 机器可快速创建起来。\n\n```\\nkubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller\\n```\n\n![image.png](14)\n\n![image.png](15)\n\n在任务执行完毕后,可以看到创建的 GPU EC2 被删除。通过 Karpenter,我们可以随时扩展资源进行训练,不需要提前配置很多 GPU 资源。\n\n![image.png](16)\n\n![image.png](17)\n\n#### **总结**\n\n\n\n通过使用 EKS, Kubeflow, Karpenter 可以建立弹性扩展性强的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台,在安装中需要注意的问题包含:\n\n\n\n1. Kubeflow 中使用了很多源是 io 的 image,可通过这个工具自动化拉取Image。\n\n2. 在中国区 Kubeflow 和 Karpenter 安装的时候,需要修改一些服务的 endpoint 和 ARN 像是 amazonaws.com 到 s3.cn-north-1.amazonaws.com.cn。Kubeflow 的配置文件代码量比较大,在部署前通过检索的方式发现需要修改的 endpoint 外。最好的办法是通过查看 Pod 运行状态进行 Troubleshooting,一般这几个配置都在 configmap 中,修改 configmap 即可。\n\n3. 在使用 Karpenter 调度 GPU 资源前,记得安装 NVIDIA 设备的插件,kubectl apply -f [https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml](https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml)。\n\n\n\n#### **参考文档**\n\n\n\n- Kubeflow on Amazon: \n[https://awslabs.github.io/kubeflow-manifests/docs/deployment/rds-s3/guide/#42-verify-s3](https://awslabs.github.io/kubeflow-manifests/docs/deployment/rds-s3/guide/#42-verify-s3)\n\n\n\n- Karpenter 介绍:\n[https://aws.amazon.com/cn/blogs/china/karpenter-new-generation-kubernetes-auto-scaling-tools/](https://aws.amazon.com/cn/blogs/china/karpenter-new-generation-kubernetes-auto-scaling-tools/)\n\n\n\n- Karpenter 安装:\n[https://karpenter.sh/v0.12.1/getting-started/getting-started-with-eksctl/](https://karpenter.sh/v0.12.1/getting-started/getting-started-with-eksctl/)\n\n##### **本篇作者**\n\n**冯秋爽**\n\n亚马逊云科技解决方案架构师,负责跨国企业级客户基于 Amazon 的技术架构设计、咨询和设计优化工作。在加入 Amazon 之前曾就职于 IBM、甲骨文等 IT 企业,积累了丰富的程序开发和数据库的实践经验。\n\n**黄德滨**\n\n亚马逊云科技资深解决方案架构师,服务于全球客户销售团队,负责技术架构设计和咨询,致力于企业级应用在 Amazon 云服务的运用和部署,对于大型企业级应用开发和实施拥有近二十年的丰富经验,在云计算领域工作多年,拥有大量帮助各种类型企业上云的经验,在加入 Amazon 之前先后服务于百度、甲骨文等国内外知名 IT 企业。\n\n","render":"<h4><a id=\\"_0\\"></a><strong>前言</strong></h4>\\n<p>随着机器学习的不断发展和在各个行业的使用,很多企业已经从最初关注构建模型、算法选择到了现在如何构建自己的机器学习平台,在该平台上实现从数据处理、模型训练、模型部署和 CI/CD。现在机器学习平台有很多,比较受欢迎的机器学习平台有亚马逊云科技的托管服务 SageMaker 和开源的 Kubeflow, MLflow 等。本文结合用户的场景,使用 Kubeflow 构建一个弹性可灵活扩展的机器学习平台。</p>\n<p>Kubeflow (<a href=\\"https://www.kubeflow.org\\" target=\\"_blank\\">https://www.kubeflow.org</a>) 是 Kubernetes 的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)工具包,目标是利用 Kubernetes 的优点,尽可能简单地扩展[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail) (ML) 模型并将它们部署到生产环境。在 Kubernetes 部署选择上,我们根据用户的使用情况选择了 [Amazon Elastic Kubernetes Service](https://aws.amazon.com/cn/eks/?trk=cndc-detail)<br />\\n(<a href=\\"https://aws.amazon.com/cn/eks/?nc1=h_ls\\" target=\\"_blank\\">https://aws.amazon.com/cn/eks/?nc1=h_ls</a>) ([Amazon EKS](https://aws.amazon.com/cn/eks/?trk=cndc-detail)) ,它是一项托管容器服务,可以在云中和本地运行和扩展 Kubernetes 应用程序。最后我们会选择三剑客中的第三项,Karpenter, Karpenter (<a href=\\"https://karpenter.sh\\" target=\\"_blank\\">https://karpenter.sh</a>) 是使用亚马逊云科技构建的开源、灵活、高性能的 Kubernetes 集群自动扩缩程序。它通过快速启动适当规模的计算资源来响应不断变化的应用程序负载,从而帮助提高应用程序可用性和集群效率。Karpenter 特别适合该用户在[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)中对于成本优化的需求,在无需配置任何 GPU 节点组情况下,快速的获得 GPU 资源进行模型训练和在训练结束后快速释放 GPU 资源。本方案中,我们会专注于使用这三个服务,构建弹性的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)平台。</p>\\n<p>本方案部署在北京区域进行,本文通过四个部分总结如何在中国区搭建 Kubeflow 1.5.1并利用 Karpenter 进行动态的 GPU 资源的扩展满足 Kubeflow ML 训练的需求。</p>\n<ul>\\n<li>准备环境</li>\n<li>部署 Kubeflow</li>\n<li>验证 Kubeflow 的安装,包含实验</li>\n<li>利用 Karpenter 进行动态的资源扩展满足 Kubeflow ML 训练的需求</li>\n</ul>\\n<p>需要的服务和架构如下图:</p>\n<p><img src=\\"1\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_30\\"></a><strong>准备环境</strong></h4>\\n<p>准备环境主要分为四部分:</p>\n<ul>\\n<li>安装必要的工具</li>\n<li>创建 EKS 集群</li>\n<li>下载源码</li>\n<li>配置 image 拉取工具</li>\n</ul>\\n<h5><a id=\\"_43\\"></a><strong>安装必要的工具</strong></h5>\\n<p>在正式安装 Kubeflow 前,需要准备一些必要的工具,具体也可参考 Kubeflow on EKS<br />\\n(<a href=\\"https://awslabs.github.io/kubeflow-manifests/docs/deployment/prerequisites/\\" target=\\"_blank\\">https://awslabs.github.io/kubeflow-manifests/docs/deployment/prerequisites/</a>) 官网。安装时请一定注意工具版本,Python 3.8 和 Kustomize 3.2.0。</p>\\n<ul>\\n<li>\\n<p>Amazon CLI<br />\\n(<a href=\\"https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html\\" target=\\"_blank\\">https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html</a>)</p>\\n</li>\n<li>\\n<p>eksctl (<a href=\\"https://eksctl.io/introduction/#installation\\" target=\\"_blank\\">https://eksctl.io/introduction/#installation</a>)</p>\\n</li>\n<li>\\n<p>kubectl (<a href=\\"https://kubernetes.io/docs/tasks/tools\\" target=\\"_blank\\">https://kubernetes.io/docs/tasks/tools</a></p>\\n</li>\n<li>\\n<p>yq (<a href=\\"https://mikefarah.gitbook.io/yq\\" target=\\"_blank\\">https://mikefarah.gitbook.io/yq</a>)</p>\\n</li>\n<li>\\n<p>jq (<a href=\\"https://stedolan.github.io/jq/download/\\" target=\\"_blank\\">https://stedolan.github.io/jq/download/</a>)</p>\\n</li>\n<li>\\n<p>kustomize version 3.2.0 (<a href=\\"https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.2.0\\" target=\\"_blank\\">https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.2.0</a>)</p>\\n</li>\n<li>\\n<p>python 3.8+ (<a href=\\"https://www.python.org/downloads/\\" target=\\"_blank\\">https://www.python.org/downloads/</a>)</p>\\n</li>\n<li>\\n<p>pip (<a href=\\"https://pip.pypa.io/en/stable/installation/\\" target=\\"_blank\\">https://pip.pypa.io/en/stable/installation/</a>)</p>\\n</li>\n</ul>\\n<h5><a id=\\"_EKS__70\\"></a><strong>创建 EKS 集群</strong></h5>\\n<p>创建一个新的集群为Kubeflow使用,关于EKS的版本选择,可以参考 Amazon EKS 和 Kubeflow 兼容性 (<a href=\\"https://awslabs.github.io/kubeflow-manifests/docs/about/eks-compatibility/\\" target=\\"_blank\\">https://awslabs.github.io/kubeflow-manifests/docs/about/eks-compatibility/</a>) 网站。</p>\\n<p>首先设置环境变量,EKS 集群名称和指定北京 Region。</p>\n<pre><code class=\\"lang-\\">export CLUSTER_NAME=kubeflow151\\nexport CLUSTER_REGION=cn-north-1\\n</code></pre>\\n<p>创建集群:</p>\n<pre><code class=\\"lang-\\">eksctl create cluster --name \${CLUSTER_NAME} --version 1.21 --region \${CLUSTER_REGION} --nodegroup-name kf --node-type m5.xlarge --nodes 4 --nodes-min 4 --nodes-max 8 --managed --with-oidc\\n</code></pre>\\n<p>下载源码</p>\n<p>此次实验基于1.5.1 进行,下载1.5.1相关的源码:</p>\n<pre><code class=\\"lang-\\">export KUBEFLOW_RELEASE_VERSION=v1.5.1\\nexport AWS_RELEASE_VERSION=v1.5.1-aws-b1.0.0\\ngit clone https://github.com/awslabs/kubeflow-manifests.git &amp;&amp; cd kubeflow-manifests\\ngit checkout \${AWS_RELEASE_VERSION}\\ngit clone --branch \${KUBEFLOW_RELEASE_VERSION} https://github.com/kubeflow/manifests.git upstream\\n</code></pre>\\n<h5><a id=\\"_image__111\\"></a><strong>配置 image 拉取工具</strong></h5>\\n<p>在安装 Kubeflow 的时候,比较困难的一个问题是 image 的拉取,例如 k8s.gcr.io (<a href=\\"https://k8s.gcr.io\\" target=\\"_blank\\">https://k8s.gcr.io</a>), gcr.io (<a href=\\"http://gcr.io\\" target=\\"_blank\\">http://gcr.io</a>), quay.io (<a href=\\"https://quay.io\\" target=\\"_blank\\">https://quay.io</a>) 等源的 image 拉取。关于这部分,我们在 [Amazon API Gateway](https://aws.amazon.com/cn/api-gateway/?trk=cndc-detail) Mutating Webhook For K8S (<a href=\\"https://github.com/aws-samples/amazon-api-gateway-mutating-webhook-for-k8\\" target=\\"_blank\\">https://github.com/aws-samples/amazon-api-gateway-mutating-webhook-for-k8</a>) 基础上做了一些修改,具体可以参考自动化拉取 image<br />\\n(<a href=\\"https://github.com/walkingerica/automate-pulling-and-mutating-webhook-for-k8\\" target=\\"_blank\\">https://github.com/walkingerica/automate-pulling-and-mutating-webhook-for-k8</a>),概括来说,原理是在需要 gcr.io 等镜像的时候,该工具自动通过 Amazon Global 区域的 CodeBuild 拉取镜像并添加到中国区的 ECR 中。</p>\\n<h4><a id=\\"_KubeFlow_119\\"></a><strong>部署 KubeFlow</strong></h4>\\n<p>在部署 KubeFlow on EKS 的时候有多种选择,除了原始安装方法外,Amazon 发行了Kubeflow on EKS 开源版本,允许客户使用现成的 Amazon 服务集成构建机器学习系统并提供安装文档, 包括 RDS 和 S3 安装方法,Cognito, RDS 和 S3 安装方法等。本篇是使用的 RDS 和S3 安装方法。此部署方法用到的服务包含:</p>\n<ul>\\n<li>RDS:代替 KFP 和 Katib 使用的 MySQL pod,用于持久化 KFP 数据(例如实验、pipelines、job 信息等)和 Katib 日志信息。</li>\n<li>S3:代替 MinIO 存储对象, 例如一些日志文件。</li>\n<li>Secret Manager:存储 RDS 相关信息,像用户名密码和 Endpoint 等。</li>\n</ul>\\n<h5><a id=\\"_131\\"></a><strong>准备工作</strong></h5>\\n<p>因为代码中没有考虑对中国区的支持,需要手动修改一些代码。</p>\n<p>在 auto-rds-s3-setup.py 文件中需要修改两处:</p>\n<ul>\\n<li>iam_policies 部分,需要把 aws 替换成 aws-cn</li>\n<li>s3_params 部分,需要把 amazonaws.com</li>\n<li>(<a href=\\"http://s3.amazonaws.com.cn\\" target=\\"_blank\\">http://s3.amazonaws.com.cn</a>) 换成 s3.amazonaws.com.cn (<a href=\\"http://s3.amazonaws.com.cn\\" target=\\"_blank\\">http://s3.amazonaws.com.cn</a>)</li>\\n</ul>\n<pre><code class=\\"lang-\\">def create_secrets_iam_service_account():\\n print(&quot;Creating secrets IAM service account...&quot;)\\n iam_policies = [\\n &quot;arn:aws-cn:iam::aws:policy/AmazonSSMReadOnlyAccess&quot;,\\n &quot;arn:aws-cn:iam::aws:policy/SecretsManagerReadWrite&quot;,\\n ]\\n\\n create_iam_service_account(\\n service_account_name=&quot;kubeflow-secrets-manager-sa&quot;,\\n namespace=&quot;kubeflow&quot;,\\n cluster_name=CLUSTER_NAME,\\n region=CLUSTER_REGION,\\n iam_policy_arns=iam_policies,\\n )\\n\\n print(&quot;Secrets IAM service account created!&quot;)\\n\\n\\ndef setup_kubeflow_pipeline():\\n print(&quot;Setting up Kubeflow Pipeline...&quot;)\\n\\n print(&quot;Retrieving DB instance info...&quot;)\\n db_instance_info = get_db_instance_info()\\n\\n pipeline_rds_params_env_file = &quot;../../awsconfigs/apps/pipeline/rds/params.env&quot;\\n pipeline_rds_secret_provider_class_file = (\\n &quot;../../awsconfigs/common/aws-secrets-manager/rds/secret-provider.yaml&quot;\\n )\\n\\n rds_params = {\\n &quot;dbHost&quot;: db_instance_info[&quot;Endpoint&quot;][&quot;Address&quot;],\\n &quot;mlmdDb&quot;: &quot;metadb&quot;,\\n }\\n edit_pipeline_params_env_file(rds_params, pipeline_rds_params_env_file)\\n\\n update_secret_provider_class(\\n pipeline_rds_secret_provider_class_file, RDS_SECRET_NAME\\n )\\n\\n pipeline_s3_params_env_file = &quot;../../awsconfigs/apps/pipeline/s3/params.env&quot;\\n pipeline_s3_secret_provider_class_file = (\\n &quot;../../awsconfigs/common/aws-secrets-manager/s3/secret-provider.yaml&quot;\\n )\\n\\n s3_params = {\\n &quot;bucketName&quot;: S3_BUCKET_NAME,\\n &quot;minioServiceRegion&quot;: CLUSTER_REGION,\\n &quot;minioServiceHost&quot;: &quot;s3.amazonaws.com.cn&quot;,\\n }\\n\\n</code></pre>\\n<p>在 config 文件中 s3 endpoint 需要修改:</p>\n<pre><code class=\\"lang-\\">{\\nartifactRepository:\\n{\\n s3: {\\n bucket: \$(kfp-artifact-bucket-name),\\n keyPrefix: artifacts,\\n endpoint: s3.cn-north-1.amazonaws.com.cn,\\n insecure: true,\\n accessKeySecret: {\\n name: mlpipeline-minio-artifact,\\n key: accesskey\\n },\\n secretKeySecret: {\\n name: mlpipeline-minio-artifact,\\n key: secretkey\\n }\\n },\\n archiveLogs: true\\n}\\n}\\n</code></pre>\\n<h5><a id=\\"_RDS_S3__Secret_Manager__229\\"></a><strong>准备 RDS, S3 和 Secret Manager 环境</strong></h5>\\n<ol>\\n<li>首先确保从代码的根目录开始。</li>\n</ol>\\n<pre><code class=\\"lang-\\">export REPO_ROOT=\$(pwd)\\n</code></pre>\\n<ol start=\\"2\\">\\n<li>进入 tests/e2e 目录并安装依赖。</li>\n</ol>\\n<pre><code class=\\"lang-\\">cd tests/e2e\\npip install -r requirements.txt\\n</code></pre>\\n<ol start=\\"3\\">\\n<li>准备需要使用的环境变量。</li>\n</ol>\\n<pre><code class=\\"lang-\\">export CLUSTER_REGION=cn-north-1\\nexport CLUSTER_NAME=kubeflow151\\nexport S3_BUCKET=&lt;YOUR S3 BUCKET&gt;\\nexport MINIO_AWS_ACCESS_KEY_ID=&lt;YOUR ACCESS KEY&gt;\\nexport MINIO_AWS_SECRET_ACCESS_KEY=&lt;YOUR SECRET ACCESS KEY&gt;\\n</code></pre>\\n<ol start=\\"4\\">\\n<li>配置 RDS, S3 和 Secret Manager 环境,安装 auto-rds-s3-setup.py。此步骤包含:</li>\n</ol>\\n<ul>\\n<li>RDS 数据库创建</li>\n<li>S3 桶创建</li>\n<li>Secret Manager 设置</li>\n<li>Serviceaccounts 创建</li>\n<li>Secret Store CSI driver 设置等</li>\n</ul>\\n<pre><code class=\\"lang-\\">PYTHONPATH=.. python utils/rds-s3/auto-rds-s3-setup.py --region \$CLUSTER_REGION --cluster \$CLUSTER_NAME --bucket \$S3_BUCKET --s3_aws_access_key_id \$MINIO_AWS_ACCESS_KEY_ID --s3_aws_secret_access_key \$MINIO_AWS_SECRET_ACCESS_KEY\\n</code></pre>\\n<p><img src=\\"2\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"3\\" alt=\\"image.png\\" /></p>\n<p>Python 脚本执行后,会看到上面的 log 输出,为了确保安装过程成功,可以分别查看 pod 运行的状态、serviceaccounts 和 CSI driver 等。</p>\n<pre><code class=\\"lang-\\">kubectl get pods —all-namespaces\\n</code></pre>\\n<p><img src=\\"4\\" alt=\\"image.png\\" /></p>\n<pre><code class=\\"lang-\\">kubectl describe serviceaccounts kubeflow-secrets-manager-sa -n kubeflow;\\n</code></pre>\\n<p><img src=\\"5\\" alt=\\"image.png\\" /></p>\n<pre><code class=\\"lang-\\">kubectl get csidriver\\n</code></pre>\\n<p><img src=\\"6\\" alt=\\"image.png\\" /></p>\n<h5><a id=\\"Kubeflow__300\\"></a><strong>Kubeflow 安装</strong></h5>\\n<p>执行如下命令安装,安装后也可以建议查看 pod 状态。</p>\n<pre><code class=\\"lang-\\">cd \$REPO_ROOT \\nwhile ! kustomize build deployments/rds-s3 | kubectl apply -f -; do echo &quot;Retrying to apply resources&quot;; sleep 30; done\\n\\nkubectl get pods --all-namespaces \\n</code></pre>\\n<p>如果各个 Pod 运行没有问题的话,执行如下命令后,就可通过 http://localhost:8080 访问 Kubeflow Dashboard, 默认用户名为 user@example.com,密码为12341234。因为涉及到 RDS 和 S3 的使用,请参考下一步验证安全结果。</p>\n<pre><code class=\\"lang-\\">kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80\\n</code></pre>\\n<p><img src=\\"7\\" alt=\\"image.png\\" /></p>\n<p>登陆后,可以看到 Kubeflow 的控制台界面如下。Kubeflow 支持的主要功能可以在界面上找到,用户编程测试工作台 (Jupyter Notebook),超参调优 (Experiment(AutoML)), 机器学习工作流(Pipeline)等。</p>\n<p><img src=\\"8\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_328\\"></a><strong>验证安装结果</strong></h4>\\n<p>在 Kubeflow 安装之后,我们通过两个方面进行验证,RDS 和 S3 的验证,这两个角度的验证也是在侧面验证超参调优和工作流工作。</p>\n<h5><a id=\\"_RDS_336\\"></a><strong>验证 RDS数据库</strong></h5>\\n<p>RDS 中会存储</p>\n<ol>\\n<li>连接 RDS 数据库。</li>\n</ol>\\n<pre><code class=\\"lang-\\">kubectl run -it —rm —image=mysql:5.7 —restart=Never mysql-client — mysql -h &lt;YOUR RDS ENDPOINT&gt; -u &lt;YOUR LOGIN&gt; -p&lt;YOUR PASSWORD&gt;\\n</code></pre>\\n<ol start=\\"2\\">\\n<li>连接成功后,查看 kubeflow 和mlpipeline 数据是否存在, 同时查看在mlpipeline中是否有如下的表。</li>\n</ol>\\n<pre><code class=\\"lang-\\">show databases;\\nuse mlpipeline; show tables;\\n</code></pre>\\n<p><img src=\\"9\\" alt=\\"image.png\\" /></p>\n<ol start=\\"3\\">\\n<li>登录进入到 Kubeflow Dashboard,使用此 yaml<br />\\n(<a href=\\"https://github.com/awslabs/kubeflow-manifests/blob/main/tests/e2e/resources/custom-resource-templates/katib-experiment-random.yaml\\" target=\\"_blank\\">https://github.com/awslabs/kubeflow-manifests/blob/main/tests/e2e/resources/custom-resource-templates/katib-experiment-random.yaml</a>) 文件(注意需要更改 namespace) 运行一个实验。具体操作为 Dashboard –&gt; Experiments (AutoML) –&gt; New Experiment。</li>\\n</ol>\n<p><img src=\\"10\\" alt=\\"image.png\\" /></p>\n<p>实验成功后,RDS 中表中会有相关的实验执行信息。</p>\n<p><img src=\\"11\\" alt=\\"image.png\\" /></p>\n<h5><a id=\\"_S3_367\\"></a><strong>验证 S3</strong></h5>\\n<p>在 Kubeflow Dashboard 中,创建一个 Experiment 并运行,运行结束之后,我们可以去到第二步部署的 S3 bucket 中,如果可以查看到 log, S3 部分没有问题。可以参考下图:</p>\n<p><img src=\\"12\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"13\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_Karpenter__Kubeflow_ML__379\\"></a><strong>利用 Karpenter 进行动态的资源扩展满足 Kubeflow ML 训练的需求</strong></h4>\\n<p>在 Karpenter 之前,EKS 用户使用 Cluster Autoscaler 动态调整集群的计算容量,他的原理是使用 Amazon EC2 Auto Scaling 组</p>\n<p>(https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html)进行扩展底层的 EC2 资源。Karpenter 会观察未调度的一组容器 (pod) 的总资源请求,然后向 Amazon EC2 直接发送命令并作出启动和终止新节点的决策,从而减少调度延迟并降低基础设施成本。在机器学习场景下,用户可以像该文中一样使用一个 EKS 节点组安装和管理 Kubeflow,在提交训练任务时,通过 Karpenter 开启 GPU 资源,在训练结束后终止 GPU 资源。</p>\n<p>Karpenter 的安装不在此介绍了,可以参考官方文档安装 (<a href=\\"https://karpenter.sh/v0.5.5/getting-started/\\" target=\\"_blank\\">https://karpenter.sh/v0.5.5/getting-started/</a>)。我们主要演示在 Karpenter 部署后,Kubeflow 中如何使用。使用验证 RDS 的例子,在 spec 中添加 resource 为 nvidia.com/gpu (<a href=\\"https://www.nvidia.com/gpu/\\" target=\\"_blank\\">https://www.nvidia.com/gpu/</a>), 添加后在 Kubeflow Dashboard 中 Experiments (AutoML) 部分运行修改后的 yaml 文件。</p>\\n<pre><code class=\\"lang-\\">.......\\n trialSpec:\\n apiVersion: batch/v1\\n kind: Job\\n spec:\\n template:\\n metadata:\\n annotations:\\n sidecar.istio.io/inject: 'false'\\n spec:\\n containers:\\n - name: training-container\\n image: docker.io/kubeflowkatib/mxnet-mnist:v1beta1-45c5727\\n command:\\n - &quot;python3&quot;\\n - &quot;/opt/mxnet-mnist/mnist.py&quot;\\n - &quot;--batch-size=64&quot;\\n - &quot;--lr=\${trialParameters.learningRate}&quot;\\n - &quot;--num-layers=\${trialParameters.numberLayers}&quot;\\n - &quot;--optimizer=\${trialParameters.optimizer}&quot;\\n resources:\\n limits:\\n nvidia.com/gpu: 1\\n restartPolicy: Never\\n</code></pre>\\n<p>在提交了这个 Experiment 后,可以通过命令行查看 Karpenter 的日志。我们可以看到 GPU 机器可快速创建起来。</p>\n<pre><code class=\\"lang-\\">kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller\\n</code></pre>\\n<p><img src=\\"14\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"15\\" alt=\\"image.png\\" /></p>\n<p>在任务执行完毕后,可以看到创建的 GPU EC2 被删除。通过 Karpenter,我们可以随时扩展资源进行训练,不需要提前配置很多 GPU 资源。</p>\n<p><img src=\\"16\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"17\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_438\\"></a><strong>总结</strong></h4>\\n<p>通过使用 EKS, Kubeflow, Karpenter 可以建立弹性扩展性强的机器学习平台,在安装中需要注意的问题包含:</p>\n<ol>\\n<li>\\n<p>Kubeflow 中使用了很多源是 io 的 image,可通过这个工具自动化拉取Image。</p>\n</li>\\n<li>\\n<p>在中国区 Kubeflow 和 Karpenter 安装的时候,需要修改一些服务的 endpoint 和 ARN 像是 amazonaws.com 到 s3.cn-north-1.amazonaws.com.cn。Kubeflow 的配置文件代码量比较大,在部署前通过检索的方式发现需要修改的 endpoint 外。最好的办法是通过查看 Pod 运行状态进行 Troubleshooting,一般这几个配置都在 configmap 中,修改 configmap 即可。</p>\n</li>\\n<li>\\n<p>在使用 Karpenter 调度 GPU 资源前,记得安装 NVIDIA 设备的插件,kubectl apply -f <a href=\\"https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml\\" target=\\"_blank\\">https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml</a>。</p>\\n</li>\n</ol>\\n<h4><a id=\\"_454\\"></a><strong>参考文档</strong></h4>\\n<ul>\\n<li>\\n<p>Kubeflow on Amazon:<br />\\n<a href=\\"https://awslabs.github.io/kubeflow-manifests/docs/deployment/rds-s3/guide/#42-verify-s3\\" target=\\"_blank\\">https://awslabs.github.io/kubeflow-manifests/docs/deployment/rds-s3/guide/#42-verify-s3</a></p>\\n</li>\n<li>\\n<p>Karpenter 介绍:<br />\\n<a href=\\"https://aws.amazon.com/cn/blogs/china/karpenter-new-generation-kubernetes-auto-scaling-tools/\\" target=\\"_blank\\">https://aws.amazon.com/cn/blogs/china/karpenter-new-generation-kubernetes-auto-scaling-tools/</a></p>\\n</li>\n<li>\\n<p>Karpenter 安装:<br />\\n<a href=\\"https://karpenter.sh/v0.12.1/getting-started/getting-started-with-eksctl/\\" target=\\"_blank\\">https://karpenter.sh/v0.12.1/getting-started/getting-started-with-eksctl/</a></p>\\n</li>\n</ul>\\n<h5><a id=\\"_471\\"></a><strong>本篇作者</strong></h5>\\n<p><strong>冯秋爽</strong></p>\\n<p>亚马逊云科技解决方案架构师,负责跨国企业级客户基于 Amazon 的技术架构设计、咨询和设计优化工作。在加入 Amazon 之前曾就职于 IBM、甲骨文等 IT 企业,积累了丰富的程序开发和数据库的实践经验。</p>\n<p><strong>黄德滨</strong></p>\\n<p>亚马逊云科技资深解决方案架构师,服务于全球客户销售团队,负责技术架构设计和咨询,致力于企业级应用在 Amazon 云服务的运用和部署,对于大型企业级应用开发和实施拥有近二十年的丰富经验,在云计算领域工作多年,拥有大量帮助各种类型企业上云的经验,在加入 Amazon 之前先后服务于百度、甲骨文等国内外知名 IT 企业。</p>\n"}
目录
亚马逊云科技解决方案 基于行业客户应用场景及技术领域的解决方案
联系亚马逊云科技专家
亚马逊云科技解决方案
基于行业客户应用场景及技术领域的解决方案
联系专家
0
目录
关闭