AttachCluster最佳實(shí)踐
0 背景
AttachCluster作業(yè)是批量計(jì)算最新推出的作業(yè)類(lèi)型。它結(jié)合了固定集群作業(yè)和AutoCluster作業(yè)的優(yōu)勢(shì),既能自動(dòng)管理集群生命周期,彈性伸縮資源,又能使用分布式緩存節(jié)省資源。本文的目的在于介紹在阿里云批量計(jì)算服務(wù)上運(yùn)行AttachCluster作業(yè)。
1 使用限制
- 支持創(chuàng)建集群時(shí)自定義系統(tǒng)盤(pán)和數(shù)據(jù)盤(pán)大小
不支持作業(yè)中自定義系統(tǒng)盤(pán)
創(chuàng)建默認(rèn)集群中定義實(shí)例系統(tǒng)盤(pán)大小為SystemDiskSize之后,提交到該集群中的所有AttachCluster作業(yè)都默認(rèn)設(shè)置為SystemDiskSize。提交job的時(shí)候,該字段填0或者不填寫(xiě)。
不支持作業(yè)中自定義數(shù)據(jù)
創(chuàng)建默認(rèn)集群中定義實(shí)例系統(tǒng)盤(pán)大小為SystemDiskSize之后,提交到該集群中的所有AttachCluster作業(yè)都默認(rèn)設(shè)置為DataDiskSize。提交job的時(shí)候,該字段填0或者不填寫(xiě)。
不支持APP作業(yè)模式, 支持DAG作業(yè)模式
作業(yè)中填寫(xiě)的鏡像必須是m-xxx開(kāi)頭的鏡像, 不是img開(kāi)頭的鏡像(提交job的時(shí)候務(wù)必仔細(xì)檢查這里?。?/strong>
2 準(zhǔn)備工作
2.1 開(kāi)通阿里云批量計(jì)算服務(wù)
要使用批量計(jì)算服務(wù),請(qǐng)根據(jù)官方文檔里面的指導(dǎo)開(kāi)通批量計(jì)算和其依賴(lài)的相關(guān)服務(wù),如OSS等。
2.2 升級(jí)Python SDK
若您未安裝批量計(jì)算Python SDK,請(qǐng)您參照安裝方法安裝該SDK。如果您檢查已經(jīng)安裝之后,請(qǐng)您參照Python SDK升級(jí)方法, 升級(jí)批量計(jì)算Python SDK至最新版。
3 創(chuàng)建集群
AttachCluster作業(yè)首次使用時(shí),需要?jiǎng)?chuàng)建一個(gè)集群,創(chuàng)建方法可參考官方文檔 。該集群對(duì)配置沒(méi)有特殊需求,實(shí)例數(shù)可設(shè)置為0。以下是創(chuàng)建集群的Python源代碼。
import time
import random
import string
import batchcompute
from batchcompute import CN_SHENZHEN as REGION
from batchcompute import Client, ClientError
from batchcompute.resources import (
JobDescription, TaskDescription, DAG,
GroupDescription, ClusterDescription,
Configs, Networks, VPC, Classic, Mounts, Notification, Topic
)
ACCESS_KEY_ID = 'Your Access Key Id'
ACCESS_KEY_SECRET = 'Your Access Key Secret'
IMAGE_ID = 'img-ubuntu'
INSTANCE_TYPE = 'ecs.sn2ne.large'
client = Client(REGION, ACCESS_KEY_ID, ACCESS_KEY_SECRET)
def create_cluster(idempotent_token=''):
try:
# Cluster description.
cluster_desc = ClusterDescription()
cluster_desc.Name = "test-cluster"
cluster_desc.Description = "demo"
cluster_desc.ImageId = IMAGE_ID
cluster_desc.InstanceType = INSTANCE_TYPE
#Group description
group_desc1 = GroupDescription()
group_desc1.DesiredVMCount = 4
group_desc1.InstanceType = 'ecs.sn1ne.large' #user group special instance type
group_desc1.ResourceType = 'OnDemand'
cluster_desc.add_group('group1', group_desc1)
#cluster_desc.add_group('group2', group_desc2)
#Configs
configs = Configs()
#Configs.Disks
configs.add_system_disk(50, 'cloud_efficiency')
configs.add_data_disk(500, 'cloud_efficiency', '/home/my-data-disk')
#Configs.Networks
networks = Networks()
vpc = VPC()
vpc.CidrBlock = '192.168.0.0/16'
#vpc.VpcId = 'vpc-xxxxx'
networks.VPC = vpc
configs.Networks = networks
cluster_desc.Configs = configs
print cluster_desc
rsp = client.create_cluster(cluster_desc, idempotent_token)
# get cluster id for attach cluster job
return rsp.Id
except ClientError, e:
print (e.get_status_code(), e.get_code(), e.get_requestid(), e.get_msg())
return ""
if __name__ == '__main__':
#Not Use idempotent token
cluster_id = create_cluster()
print cluster_id
3 創(chuàng)建作業(yè)
在創(chuàng)建作業(yè)的時(shí)候需要步驟2中的集群Id,填入task的AutoCluster的ClusterId字段中。以下是創(chuàng)建作業(yè)的Python源代碼。
from batchcompute import Client, ClientError
from batchcompute import CN_SHENZHEN as REGION
from batchcompute.resources import (
ClusterDescription, GroupDescription, Configs, Networks, VPC,
JobDescription, TaskDescription, DAG,Mounts,
AutoCluster,Disks,Notification,
)
access_key_id = "" # your access key id
access_key_secret = "" # your access key secret
image_id = "m-8vbd8lo9xxxx" # the id of a image created before,鏡像需要確保已經(jīng)注冊(cè)給批量計(jì)算,且必須是m-xx開(kāi)頭的鏡像,不是img開(kāi)頭的鏡像
instance_type = "ecs.sn1.medium" # instance type
inputOssPath = "oss://xxx/input/" # your input oss path
outputOssPath = "oss://xxx/output/" #your output oss path
stdoutOssPath = "oss://xxx/log/stdout/" #your stdout oss path
stderrOssPath = "oss://xxx/log/stderr/" #your stderr oss path
def getAutoClusterDesc():
auto_desc = AutoCluster()
# attach cluster這里里填入上一步創(chuàng)建的集群Id
auto_desc.ClusterId = cls-xxxxx
auto_desc.ImageId = image_id
auto_desc.ReserveOnFail = False
# 實(shí)例規(guī)格
auto_desc.InstanceType = instance_type
#case1 設(shè)置上限價(jià)格的競(jìng)價(jià)實(shí)例;
# auto_desc.ResourceType = "Spot"
# auto_desc.SpotStrategy = "SpotWithPriceLimit"
# auto_desc.SpotPriceLimit = 0.5
#case2 系統(tǒng)自動(dòng)出價(jià),最高按量付費(fèi)價(jià)格
# auto_desc.ResourceType = "Spot"
# auto_desc.SpotStrategy = "SpotAsPriceGo"
#case3 按量
auto_desc.ResourceType = "OnDemand"
#Configs
configs = Configs()
#Configs.Networks
networks = Networks()
vpc = VPC()
#case1 只給CidrBlock
vpc.CidrBlock = '192.168.0.0/16'
#case2 CidrBlock和VpcId 都傳入,必須保證VpcId的CidrBlock 和傳入的CidrBlock保持一致
# vpc.CidrBlock = '172.26.0.0/16'
# vpc.VpcId = "vpc-8vbfxdyhxxxx"
networks.VPC = vpc
configs.Networks = networks
# 不支持設(shè)置系統(tǒng)盤(pán)
#configs.add_system_disk(size=0, type_='cloud_efficiency')
#不支持設(shè)置數(shù)據(jù)盤(pán)
# case1 linux環(huán)境
# configs.add_data_disk(size=0, type_='cloud_efficiency', mount_point='/path/to/mount/')
# case2 windows環(huán)境
# configs.add_data_disk(size=0, type_='cloud_efficiency', mount_point='E:')
# 設(shè)置節(jié)點(diǎn)個(gè)數(shù)
configs.InstanceCount = 1
auto_desc.Configs = configs
return auto_desc
def getDagJobDesc(clusterId = None):
job_desc = JobDescription()
dag_desc = DAG()
mounts_desc = Mounts()
job_desc.Name = "testBatchSdkJob"
job_desc.Description = "test job"
job_desc.Priority = 1
# 訂閱job完成或者失敗事件
noti_desc = Notification()
noti_desc.Topic['Name'] = "test-topic"
noti_desc.Topic['Endpoint'] = "http://[UserId].mns.[Region].aliyuncs.com/"
noti_desc.Topic['Events'] = ["OnJobFinished", "OnJobFailed"]
# job_desc.Notification = noti_desc
job_desc.JobFailOnInstanceFail = False
# 作業(yè)運(yùn)行成功后戶自動(dòng)會(huì)被立即釋放掉
job_desc.AutoRelease = False
job_desc.Type = "DAG"
echo_task = TaskDescription()
# echo_task.InputMapping = {"oss://xxx/input/": "/home/test/input/",
# "oss://xxx/test/file": "/home/test/test/file"}
echo_task.InputMapping = {inputOssPath: "/home/test/input/"}
echo_task.OutputMapping = {"/home/test/output/":outputOssPath}
#觸發(fā)程序運(yùn)行的命令行
#case1 執(zhí)行l(wèi)inux命令行
echo_task.Parameters.Command.CommandLine = "/bin/bash -c 'echo BatchcomputeService'"
#case2 執(zhí)行Windows CMD.exe
# echo_task.Parameters.Command.CommandLine = "cmd /c 'echo BatchcomputeService'"
#case3 輸入可執(zhí)行文件
# PackagePath存放commandLine中的可執(zhí)行文件或者二進(jìn)制包
# echo_task.Parameters.Command.PackagePath = "oss://xxx/package/test.sh"
# echo_task.Parameters.Command.CommandLine = "sh test.sh"
# 設(shè)置程序運(yùn)行過(guò)程中相關(guān)環(huán)境變量信息
echo_task.Parameters.Command.EnvVars["key1"] = "value1"
echo_task.Parameters.Command.EnvVars["key2"] = "value2"
# 設(shè)置程序的標(biāo)準(zhǔn)輸出地址,程序中的print打印會(huì)實(shí)時(shí)上傳到指定的oss地址
echo_task.Parameters.StdoutRedirectPath = stdoutOssPath
# 設(shè)置程序的標(biāo)準(zhǔn)錯(cuò)誤輸出地址,程序拋出的異常錯(cuò)誤會(huì)實(shí)時(shí)上傳到指定的oss地址
echo_task.Parameters.StderrRedirectPath = stderrOssPath
# 設(shè)置任務(wù)的超時(shí)時(shí)間
echo_task.Timeout = 600
# 設(shè)置任務(wù)所需實(shí)例個(gè)數(shù)
# 環(huán)境變量BATCH_COMPUTE_INSTANCE_ID為0到InstanceCount-1
# 在執(zhí)行程序中訪問(wèn)BATCH_COMPUTE_INSTANCE_ID,實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)的切片實(shí)現(xiàn)單任務(wù)并發(fā)執(zhí)行
echo_task.InstanceCount = 1
# 設(shè)置任務(wù)失敗后重試次數(shù)
echo_task.MaxRetryCount = 0
# NAS數(shù)據(jù)掛載
#采用NAS時(shí)必須保證網(wǎng)絡(luò)和NAS在同一個(gè)VPC內(nèi)
nasMountEntry = {
"Source": "nas://xxxx.nas.aliyuncs.com:/",
"Destination": "/home/mnt/",
"WriteSupport":True,
}
mounts_desc.add_entry(nasMountEntry)
mounts_desc.Locale = "utf-8"
mounts_desc.Lock = False
# echo_task.Mounts = mounts_desc
# attach cluster作業(yè)該集群字段設(shè)置為空
echo_task.ClusterId = ""
echo_task.AutoCluster = getAutoClusterDesc()
# 添加任務(wù)
dag_desc.add_task('echoTask', echo_task)
# 可以設(shè)置多個(gè)task,每個(gè)task可以根據(jù)需求進(jìn)行設(shè)置各項(xiàng)參數(shù)
# dag_desc.add_task('echoTask2', echo_task)
# Dependencies設(shè)置多個(gè)task之間的依賴(lài)關(guān)系,echoTask2依賴(lài)echoTask;echoTask3依賴(lài)echoTask2
# dag_desc.Dependencies = {"echoTask":["echoTask2"], "echoTask2":["echoTask3"]}
job_desc.DAG = dag_desc
return job_desc
if __name__ == "__main__":
client = Client(REGION, access_key_id, access_key_secret)
try:
job_desc = getDagJobDesc()
job_id = client.create_job(job_desc).Id
print('job created: %s' % job_id)
except ClientError,e:
print (e.get_status_code(), e.get_code(), e.get_requestid(), e.get_msg())
AttachCluster作業(yè)創(chuàng)建已經(jīng)完成。