1) Create token github and heml chart
Đâu tiên bạn cũng cần chuẩn bị github và token, helm chart
Bạn sẽ cần tìm hiểu link sau:
https://nimtechnology.com/2022/05/14/spinnaker-design-cd-on-kubernetes-by-spinnaker/#1_Preparing
2) Design template spinnaker
Mình sẽ cần cung cấp cho bạn 1 template mẫu:
{
"schema": "v2",
"variables": [
{
"type": "<type>",
"defaultValue": <value>,
"description": "<description>",
"name": "<varName>"
}
],
"id": "<templateName>", # The pipeline instance references the template using this
"protect": <true | false>,
"metadata": {
"name": "displayName", # The display name shown in Deck
"description": "<description>",
"owner": "example@example.com",
"scopes": ["global"] # Not used
},
"pipeline": { # Contains the templatized pipeline itself
"lastModifiedBy": "anonymous", # Not used
"updateTs": "0", # Not used
"parameterConfig": [], # Same as in a regular pipeline
"limitConcurrent": true, # Same as in a regular pipeline
"keepWaitingPipelines": false, # Same as in a regular pipeline
"description": "", # Same as in a regular pipeline
"triggers": [], # Same as in a regular pipeline
"notifications": [], # Same as in a regular pipeline
"stages": [ # Contains the templated stages
{
# This one is an example stage:
"waitTime": "${ templateVariables.waitTime }", # Templated field.
"name": "My Wait Stage",
"type": "wait",
"refId": "wait1",
"requisiteStageRefIds": []
}
]
}
}
Hoặc bạn lấy template ở link này:
https://spinnaker.io/docs/reference/pipeline/templates/
Đầu tiên chúng ta sẽ tạo ra các stage.
Theo mình cách dễ nhất là bạn chỉnh trên UI xong bạn export ra Json -> rổi thế vào file bên trên.
state đâu tiên:
#######stage 1 Get Manifest
{
"account": "cluster1",
"app": "manual-create-app",
"cloudProvider": "kubernetes",
"location": "default",
"manifestName": "deployment default-nimtechnology",
"mode": "static",
"name": "Get Manifest",
"refId": "1",
"requisiteStageRefIds": [],
"type": "findArtifactsFromResource"
}
MÌnh sẽ giải thích các thành phần cần thiết
account: context trong kubeconfig hay còn gọi là tên cluster k8s
app: tên application của spinnaker
location: là namespace
manifestName: nó gồm 2 thành phần là <Kind: deployment, ingress,…> <nameOfWordload>

mode: nếu là static thì nó sẽ đọc theo những j bạn chỉ định ở manifestName.
name: đặt tên cho stage này
type: findArtifactsFromResource => chức năng của stage này là lấy thông tin workload đang run trên k8s nên ta chọn type này
Nếu chúng ta làm template thì với 1 mục đích là tải sử dụng nhiều lần với nhiều deployment khác nhau.
Chúng ta phải define các variables
mình sẽ đưa line code ví dụ.
"manifestName": "${ templateVariables.kind } ${ templateVariables.workloadName }",

với từng variable thì chúng ta cần định nghĩa chúng
"variables": [
{
"type": "string",
"defaultValue": deployment,
"description": "kind Of workload such as: deployemt, statefulset",
"name": "kind"
},
{
"type": "string",
"defaultValue": nimtechnology,
"description": "this is the workload name",
"name": "workloadName"
}
]
defaultValue: Chỗ này nghĩ là nếu bạn không đưa data vào thì mặc định lấy value ở đây để sử dụng.

Tiếp theo là bạn chỉnh thêm phần sau:

"id": "<templateName>", # The pipeline instance references the template using this
"protect": <true | false>,
"metadata": {
"name": "displayName", # The display name shown in Deck
"description": "<description>",
"owner": "example@example.com",
"scopes": ["global"] # Not used
}
id: định danh của template, khi bạn muốn sử dụng thì giọi ID của template
protect: bạn để là false
metadata:
name: Tên của template, dụng để hiển thị bên ngoài
owner: Bạn có thể để email hoặc thông tin của bạn ở đây
Giờ thì mình có 1 template như sau:
{
"schema": "v2",
"variables": [
{
"type": "string",
"defaultValue": "deployment",
"description": "kind Of workload such as: deployemt, statefulset",
"name": "kind"
},
{
"type": "string",
"defaultValue": "nimtechnology",
"description": "this is the workload name",
"name": "workloadName"
}
],
"id": "nimtSpinnakerTemplateV1",
"protect": false,
"metadata": {
"name": "Nimtechnology Spinnaker Template V1",
"description": "Study spinnaker together!!!",
"owner": "mr.nim94@gmail.com",
"scopes": ["global"]
},
"pipeline": {
"lastModifiedBy": "anonymous",
"updateTs": "0",
"parameterConfig": [],
"limitConcurrent": true,
"keepWaitingPipelines": false,
"description": "",
"triggers": [],
"notifications": [],
"stages": [
{
"account": "cluster1",
"app": "manual-create-app",
"cloudProvider": "kubernetes",
"location": "default",
"manifestName": "${ templateVariables.kind } ${ templateVariables.workloadName }",
"mode": "static",
"name": "Get Manifest",
"refId": "1",
"requisiteStageRefIds": [],
"type": "findArtifactsFromResource"
}
]
}
}
Giờ bạn cần chạy lên spinnaker CLI
Tham khảo link sau:
Install Spin CLI and config it to integrate with Google OAuth2
Bạn cần tạo ra 1 file config:
##file: config-nimtechnology ########### Gate: Endpoint: http://spin.nimtechnology.com/gate
Bạn gõ command:
spin application list --config config-nimtechnology

mình sử dụng command spin để lưu template lại
spin pt save --file template-spin-nimtechnology-v1.json --config config-nimtechnology
Mình gặp lỗi:
Encountered an error with saving pipeline template map[application:global buildTime:1.652552232113e+12 endTime:1.65255223227e+12 execution:map[application:global authentication:map[allowedAccounts:[cluster1 dockerhub] user:anonymous] buildTime:1.652552232113e+12 canceled:false description:Create pipeline template 'Nimtechnology Spinnaker Template V1' endTime:1.65255223227e+12 id:01G31WKV5HQ2D4WJ6XC3DKRMKN initialConfig:map[] keepWaitingPipelines:false limitConcurrent:false notifications:[] origin:api stages:[map[context:map[beforeStagePlanningFailed:true exception:map[details:map[error:Unexpected Task Failure errors:[No StageDefinitionBuilder implementation for createV2PipelineTemplate(alias: null) found (knownTypes: googleCloudBuild,upsertDeliveryConfig,shrinkCluster,reorderPipelines,upsertLoadBalancers,resumeRolloutManifest,modifyAsgLaunchConfiguration,remote,upsertEntityTags,deleteSnapshot,deregisterInstancesFromLoadBalancer,bulkUpsertEntityTags,quickPatch,deleteLaunchConfiguration,destroyAsg,runJob,deployCloudFormation,checkPreconditions,determineTargetReference,clouddriverClearAltTablespace,upsertSecurityGroup,manualJudgment,upsertLoadBalancer,getProperties,modifyGceAutoscalingPolicy,disableCluster,deployService,script,restoreSnapshot,gremlin,disableManifest,terminateInstanceAndDecrementServerGroup,copyAmazonLoadBalancer,rollbackCluster,disableInstancesInDiscovery,cloneServerGroup,updatePipeline,deleteLaunchTemplate,bakeCloudFoundryManifest,setStatefulDisk,wait,monitorPipeline,serverGroupForceCacheRefresh,statefullyUpdateBootImage,deleteTencentCloudScheduledAction,upsertDisruptionBudget,saveSnapshot,upsertAmazonDNS,findImage,scaleManifest,awsCodeBuild,undoRolloutManifest,noop,upsertAsgScheduledActions,enableInstancesInDiscovery,deleteEntityTags,concourse,destroyService,findArtifactsFromResource,registerInstancesWithLoadBalancer,jenkins,rebootInstances,rollbackServerGroup,upsertServerGroupTags,captureSourceServerGroupCapacity,upsertPluginInfo,destroyJob,cloudOperation,bulkQuickPatch,deployManifest,scaleDownCluster,findImageFromTags,pipeline,upsertScalingPolicy,upsertProject,detachInstances,updateApplication,preconfiguredWebhook,createApplication,deleteDeliveryConfig,unmapLoadBalancers,terminateInstanceAndDecrementAsg,modifyAwsScalingProcess,rollingPush,shareService,enableServerGroup,disableServerGroup,savePipelinesFromArtifact,webhook,deleteLoadBalancer,createServiceKey,resizeServerGroup,waitUntil,patchManifest,deploy,deleteManifest,lambdaFunction,upsertAmazonLoadBalancer,evaluateVariables,determineTargetServerGroup,updateJobProcesses,deleteImage,enableManifest,setPreferredPluginRelease,jira,deleteSecurityGroup,upsertAsgTags,enableAsg,wercker,waitForCondition,deleteProject,updateLaunchTemplate,preconfiguredJob,copySecurityGroup,mapLoadBalancers,restrictExecutionDuringTimeWindow,loadPluginRelease,terminateInstances,savePipeline,pauseRolloutManifest,startAppEngineServerGroup,dependsOnExecution,upsertTencentCloudScheduledActions,updateSecurityGroupsForServerGroup,modifyScalingProcess,upsertApplication,applySourceServerGroupCapacity,updateLaunchConfig,findArtifactFromExecution,bakeManifest,upsertAppEngineLoadBalancers,stopAppEngineServerGroup,copyLastAsg,pinServerGroup,upsertImageTags,deleteApplication,modifyScalingGroup,cloudFoundryCreateServiceBindings,rollingRestartManifest,bulkDestroyServerGroup,disableAsg,modifyAsg,unshareService,pageApplicationOwner,createServerGroup,deleteAmazonLoadBalancer,deleteScalingPolicy,bake,travis,destroyServerGroup,deleteServiceKey,deployAppEngineConfiguration)] stackTrace:com.netflix.spinnaker.orca.StageResolver$NoSuchStageDefinitionBuilderException: No StageDefinitionBuilder implementation for createV2PipelineTemplate(alias: null) found (knownTypes: googleCloudBuild,upsertDeliveryConfig,shrinkCluster,reorderPipelines,upsertLoadBalancers,resumeRolloutManifest,modifyAsgLaunchConfiguration,remote,upsertEntityTags,deleteSnapshot,deregisterInstancesFromLoadBalancer,bulkUpsertEntityTags,quickPatch,deleteLaunchConfiguration,destroyAsg,runJob,deployCloudFormation,checkPreconditions,determineTargetReference,clouddriverClearAltTablespace,upsertSecurityGroup,manualJudgment,upsertLoadBalancer,getProperties,modifyGceAutoscalingPolicy,disableCluster,deployService,script,restoreSnapshot,gremlin,disableManifest,terminateInstanceAndDecrementServerGroup,copyAmazonLoadBalancer,rollbackCluster,disableInstancesInDiscovery,cloneServerGroup,updatePipeline,deleteLaunchTemplate,bakeCloudFoundryManifest,setStatefulDisk,wait,monitorPipeline,serverGroupForceCacheRefresh,statefullyUpdateBootImage,deleteTencentCloudScheduledAction,upsertDisruptionBudget,saveSnapshot,upsertAmazonDNS,findImage,scaleManifest,awsCodeBuild,undoRolloutManifest,noop,upsertAsgScheduledActions,enableInstancesInDiscovery,deleteEntityTags,concourse,destroyService,findArtifactsFromResource,registerInstancesWithLoadBalancer,jenkins,rebootInstances,rollbackServerGroup,upsertServerGroupTags,captureSourceServerGroupCapacity,upsertPluginInfo,destroyJob,cloudOperation,bulkQuickPatch,deployManifest,scaleDownCluster,findImageFromTags,pipeline,upsertScalingPolicy,upsertProject,detachInstances,updateApplication,preconfiguredWebhook,createApplication,deleteDeliveryConfig,unmapLoadBalancers,terminateInstanceAndDecrementAsg,modifyAwsScalingProcess,rollingPush,shareService,enableServerGroup,disableServerGroup,savePipelinesFromArtifact,webhook,deleteLoadBalancer,createServiceKey,resizeServerGroup,waitUntil,patchManifest,deploy,deleteManifest,lambdaFunction,upsertAmazonLoadBalancer,evaluateVariables,determineTargetServerGroup,updateJobProcesses,deleteImage,enableManifest,setPreferredPluginRelease,jira,deleteSecurityGroup,upsertAsgTags,enableAsg,wercker,waitForCondition,deleteProject,updateLaunchTemplate,preconfiguredJob,copySecurityGroup,mapLoadBalancers,restrictExecutionDuringTimeWindow,loadPluginRelease,terminateInstances,savePipeline,pauseRolloutManifest,startAppEngineServerGroup,dependsOnExecution,upsertTencentCloudScheduledActions,updateSecurityGroupsForServerGroup,modifyScalingProcess,upsertApplication,applySourceServerGroupCapacity,updateLaunchConfig,findArtifactFromExecution,bakeManifest,upsertAppEngineLoadBalancers,stopAppEngineServerGroup,copyLastAsg,pinServerGroup,upsertImageTags,deleteApplication,modifyScalingGroup,cloudFoundryCreateServiceBindings,rollingRestartManifest,bulkDestroyServerGroup,disableAsg,modifyAsg,unshareService,pageApplicationOwner,createServerGroup,deleteAmazonLoadBalancer,deleteScalingPolicy,bake,travis,destroyServerGroup,deleteServiceKey,deployAppEngineConfiguration) at com.netflix.spinnaker.orca.DefaultStageResolver.getStageDefinitionBuilder(DefaultStageResolver.java:75) at com.netflix.spinnaker.orca.pipeline.util.StageNavigator.lambda$ancestors$0(StageNavigator.java:51) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) at java.base/java.util.Collections$2.tryAdvance(Collections.java:4747) at java.base/java.util.Collections$2.forEachRemaining(Collections.java:4755) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at com.netflix.spinnaker.orca.pipeline.util.StageNavigator.ancestors(StageNavigator.java:53) at com.netflix.spinnaker.orca.q.handler.AuthenticationAware$DefaultImpls.withAuth(AuthenticationAware.kt:32) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withAuth(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler$handle$1.invoke(CompleteStageHandler.kt:119) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler$handle$1.invoke(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$withStage$1.invoke(OrcaMessageHandler.kt:85) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$withStage$1.invoke(OrcaMessageHandler.kt:46) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.withExecution(OrcaMessageHandler.kt:95) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withExecution(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.withStage(OrcaMessageHandler.kt:74) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withStage(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.handle(CompleteStageHandler.kt:85) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.handle(CompleteStageHandler.kt:72) at com.netflix.spinnaker.q.MessageHandler$DefaultImpls.invoke(MessageHandler.kt:36) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.invoke(OrcaMessageHandler.kt) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.invoke(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.audit.ExecutionTrackingMessageHandlerPostProcessor$ExecutionTrackingMessageHandlerProxy.invoke(ExecutionTrackingMessageHandlerPostProcessor.kt:72) at com.netflix.spinnaker.q.QueueProcessor$callback$1$1.run(QueueProcessor.kt:90) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) ] exceptionType:NoSuchStageDefinitionBuilderException operation:createV2PipelineTemplate:ConstructAfterStages shouldRetry:false timestamp:1.652552232204e+12] pipelineTemplate:eyJpZCI6Im5pbXRTcGlubmFrZXJUZW1wbGF0ZVYxIiwibWV0YWRhdGEiOnsiZGVzY3JpcHRpb24iOiJTdHVkeSBzcGlubmFrZXIgdG9nZXRoZXIhISEiLCJuYW1lIjoiTmltdGVjaG5vbG9neSBTcGlubmFrZXIgVGVtcGxhdGUgVjEiLCJvd25lciI6Im1yLm5pbTk0QGdtYWlsLmNvbSIsInNjb3BlcyI6WyJnbG9iYWwiXX0sInBpcGVsaW5lIjp7ImRlc2NyaXB0aW9uIjoiIiwia2VlcFdhaXRpbmdQaXBlbGluZXMiOmZhbHNlLCJsYXN0TW9kaWZpZWRCeSI6ImFub255bW91cyIsImxpbWl0Q29uY3VycmVudCI6dHJ1ZSwibm90aWZpY2F0aW9ucyI6W10sInBhcmFtZXRlckNvbmZpZyI6W10sInN0YWdlcyI6W3siYWNjb3VudCI6ImRlZmF1bHQiLCJjb21wbGV0ZU90aGVyQnJhbmNoZXNUaGVuRmFpbCI6ZmFsc2UsImNvbnRpbnVlUGlwZWxpbmUiOnRydWUsImZhaWxPbkZhaWxlZEV4cHJlc3Npb25zIjpmYWxzZSwiZmFpbFBpcGVsaW5lIjpmYWxzZSwibG9jYXRpb24iOiJkZWZhdWx0IiwibWFuaWZlc3ROYW1lIjoiJHsgdGVtcGxhdGVWYXJpYWJsZXMua2luZCB9ICR7IHRlbXBsYXRlVmFyaWFibGVzLndvcmtsb2FkTmFtZSB9IiwibW9kZSI6InN0YXRpYyIsIm5hbWUiOiJHZXQgTWFuaWZlc3QiLCJyZWZJZCI6IjEiLCJyZXF1aXNpdGVTdGFnZVJlZklkcyI6W10sInJlc3RyaWN0RXhlY3V0aW9uRHVyaW5nVGltZVdpbmRvdyI6ZmFsc2UsInR5cGUiOiJmaW5kQXJ0aWZhY3RzRnJvbVJlc291cmNlIn1dLCJ0cmlnZ2VycyI6W10sInVwZGF0ZVRzIjoiMCJ9LCJwcm90ZWN0IjpmYWxzZSwic2NoZW1hIjoidjIiLCJ2YXJpYWJsZXMiOlt7ImRlZmF1bHRWYWx1ZSI6ImRlcGxveW1lbnQiLCJkZXNjcmlwdGlvbiI6ImtpbmQgT2Ygd29ya2xvYWQgc3VjaCBhczogZGVwbG95ZW10LCBzdGF0ZWZ1bHNldCIsIm5hbWUiOiJraW5kIiwidHlwZSI6InN0cmluZyJ9LHsiZGVmYXVsdFZhbHVlIjoibmltdGVjaG5vbG9neSIsImRlc2NyaXB0aW9uIjoidGhpcyBpcyB0aGUgd29ya2xvYWQgbmFtZSIsIm5hbWUiOiJ3b3JrbG9hZE5hbWUiLCJ0eXBlIjoic3RyaW5nIn1dfQ== user:anonymous] endTime:1.652552232204e+12 id:01G31WKV5HW68GM1AFPD7JFPNB name:createV2PipelineTemplate outputs:map[] refId:0 requisiteStageRefIds:[] status:TERMINAL tasks:[] type:createV2PipelineTemplate]] startTime:1.652552232138e+12 status:TERMINAL systemNotifications:[] trigger:map[artifacts:[] dryRun:false expectedArtifacts:[] notifications:[] parameters:map[] rebake:false resolvedExpectedArtifacts:[] strategy:false type:manual user:anonymous] type:ORCHESTRATION] id:01G31WKV5HQ2D4WJ6XC3DKRMKN name:Create pipeline template 'Nimtechnology Spinnaker Template V1' startTime:1.652552232138e+12 status:TERMINAL steps:[] variables:[map[key:pipelineTemplate value:eyJpZCI6Im5pbXRTcGlubmFrZXJUZW1wbGF0ZVYxIiwibWV0YWRhdGEiOnsiZGVzY3JpcHRpb24iOiJTdHVkeSBzcGlubmFrZXIgdG9nZXRoZXIhISEiLCJuYW1lIjoiTmltdGVjaG5vbG9neSBTcGlubmFrZXIgVGVtcGxhdGUgVjEiLCJvd25lciI6Im1yLm5pbTk0QGdtYWlsLmNvbSIsInNjb3BlcyI6WyJnbG9iYWwiXX0sInBpcGVsaW5lIjp7ImRlc2NyaXB0aW9uIjoiIiwia2VlcFdhaXRpbmdQaXBlbGluZXMiOmZhbHNlLCJsYXN0TW9kaWZpZWRCeSI6ImFub255bW91cyIsImxpbWl0Q29uY3VycmVudCI6dHJ1ZSwibm90aWZpY2F0aW9ucyI6W10sInBhcmFtZXRlckNvbmZpZyI6W10sInN0YWdlcyI6W3siYWNjb3VudCI6ImRlZmF1bHQiLCJjb21wbGV0ZU90aGVyQnJhbmNoZXNUaGVuRmFpbCI6ZmFsc2UsImNvbnRpbnVlUGlwZWxpbmUiOnRydWUsImZhaWxPbkZhaWxlZEV4cHJlc3Npb25zIjpmYWxzZSwiZmFpbFBpcGVsaW5lIjpmYWxzZSwibG9jYXRpb24iOiJkZWZhdWx0IiwibWFuaWZlc3ROYW1lIjoiJHsgdGVtcGxhdGVWYXJpYWJsZXMua2luZCB9ICR7IHRlbXBsYXRlVmFyaWFibGVzLndvcmtsb2FkTmFtZSB9IiwibW9kZSI6InN0YXRpYyIsIm5hbWUiOiJHZXQgTWFuaWZlc3QiLCJyZWZJZCI6IjEiLCJyZXF1aXNpdGVTdGFnZVJlZklkcyI6W10sInJlc3RyaWN0RXhlY3V0aW9uRHVyaW5nVGltZVdpbmRvdyI6ZmFsc2UsInR5cGUiOiJmaW5kQXJ0aWZhY3RzRnJvbVJlc291cmNlIn1dLCJ0cmlnZ2VycyI6W10sInVwZGF0ZVRzIjoiMCJ9LCJwcm90ZWN0IjpmYWxzZSwic2NoZW1hIjoidjIiLCJ2YXJpYWJsZXMiOlt7ImRlZmF1bHRWYWx1ZSI6ImRlcGxveW1lbnQiLCJkZXNjcmlwdGlvbiI6ImtpbmQgT2Ygd29ya2xvYWQgc3VjaCBhczogZGVwbG95ZW10LCBzdGF0ZWZ1bHNldCIsIm5hbWUiOiJraW5kIiwidHlwZSI6InN0cmluZyJ9LHsiZGVmYXVsdFZhbHVlIjoibmltdGVjaG5vbG9neSIsImRlc2NyaXB0aW9uIjoidGhpcyBpcyB0aGUgd29ya2xvYWQgbmFtZSIsIm5hbWUiOiJ3b3JrbG9hZE5hbWUiLCJ0eXBlIjoic3RyaW5nIn1dfQ==] map[key:user value:anonymous] map[key:exception value:map[details:map[error:Unexpected Task Failure errors:[No StageDefinitionBuilder implementation for createV2PipelineTemplate(alias: null) found (knownTypes: googleCloudBuild,upsertDeliveryConfig,shrinkCluster,reorderPipelines,upsertLoadBalancers,resumeRolloutManifest,modifyAsgLaunchConfiguration,remote,upsertEntityTags,deleteSnapshot,deregisterInstancesFromLoadBalancer,bulkUpsertEntityTags,quickPatch,deleteLaunchConfiguration,destroyAsg,runJob,deployCloudFormation,checkPreconditions,determineTargetReference,clouddriverClearAltTablespace,upsertSecurityGroup,manualJudgment,upsertLoadBalancer,getProperties,modifyGceAutoscalingPolicy,disableCluster,deployService,script,restoreSnapshot,gremlin,disableManifest,terminateInstanceAndDecrementServerGroup,copyAmazonLoadBalancer,rollbackCluster,disableInstancesInDiscovery,cloneServerGroup,updatePipeline,deleteLaunchTemplate,bakeCloudFoundryManifest,setStatefulDisk,wait,monitorPipeline,serverGroupForceCacheRefresh,statefullyUpdateBootImage,deleteTencentCloudScheduledAction,upsertDisruptionBudget,saveSnapshot,upsertAmazonDNS,findImage,scaleManifest,awsCodeBuild,undoRolloutManifest,noop,upsertAsgScheduledActions,enableInstancesInDiscovery,deleteEntityTags,concourse,destroyService,findArtifactsFromResource,registerInstancesWithLoadBalancer,jenkins,rebootInstances,rollbackServerGroup,upsertServerGroupTags,captureSourceServerGroupCapacity,upsertPluginInfo,destroyJob,cloudOperation,bulkQuickPatch,deployManifest,scaleDownCluster,findImageFromTags,pipeline,upsertScalingPolicy,upsertProject,detachInstances,updateApplication,preconfiguredWebhook,createApplication,deleteDeliveryConfig,unmapLoadBalancers,terminateInstanceAndDecrementAsg,modifyAwsScalingProcess,rollingPush,shareService,enableServerGroup,disableServerGroup,savePipelinesFromArtifact,webhook,deleteLoadBalancer,createServiceKey,resizeServerGroup,waitUntil,patchManifest,deploy,deleteManifest,lambdaFunction,upsertAmazonLoadBalancer,evaluateVariables,determineTargetServerGroup,updateJobProcesses,deleteImage,enableManifest,setPreferredPluginRelease,jira,deleteSecurityGroup,upsertAsgTags,enableAsg,wercker,waitForCondition,deleteProject,updateLaunchTemplate,preconfiguredJob,copySecurityGroup,mapLoadBalancers,restrictExecutionDuringTimeWindow,loadPluginRelease,terminateInstances,savePipeline,pauseRolloutManifest,startAppEngineServerGroup,dependsOnExecution,upsertTencentCloudScheduledActions,updateSecurityGroupsForServerGroup,modifyScalingProcess,upsertApplication,applySourceServerGroupCapacity,updateLaunchConfig,findArtifactFromExecution,bakeManifest,upsertAppEngineLoadBalancers,stopAppEngineServerGroup,copyLastAsg,pinServerGroup,upsertImageTags,deleteApplication,modifyScalingGroup,cloudFoundryCreateServiceBindings,rollingRestartManifest,bulkDestroyServerGroup,disableAsg,modifyAsg,unshareService,pageApplicationOwner,createServerGroup,deleteAmazonLoadBalancer,deleteScalingPolicy,bake,travis,destroyServerGroup,deleteServiceKey,deployAppEngineConfiguration)] stackTrace:com.netflix.spinnaker.orca.StageResolver$NoSuchStageDefinitionBuilderException: No StageDefinitionBuilder implementation for createV2PipelineTemplate(alias: null) found (knownTypes: googleCloudBuild,upsertDeliveryConfig,shrinkCluster,reorderPipelines,upsertLoadBalancers,resumeRolloutManifest,modifyAsgLaunchConfiguration,remote,upsertEntityTags,deleteSnapshot,deregisterInstancesFromLoadBalancer,bulkUpsertEntityTags,quickPatch,deleteLaunchConfiguration,destroyAsg,runJob,deployCloudFormation,checkPreconditions,determineTargetReference,clouddriverClearAltTablespace,upsertSecurityGroup,manualJudgment,upsertLoadBalancer,getProperties,modifyGceAutoscalingPolicy,disableCluster,deployService,script,restoreSnapshot,gremlin,disableManifest,terminateInstanceAndDecrementServerGroup,copyAmazonLoadBalancer,rollbackCluster,disableInstancesInDiscovery,cloneServerGroup,updatePipeline,deleteLaunchTemplate,bakeCloudFoundryManifest,setStatefulDisk,wait,monitorPipeline,serverGroupForceCacheRefresh,statefullyUpdateBootImage,deleteTencentCloudScheduledAction,upsertDisruptionBudget,saveSnapshot,upsertAmazonDNS,findImage,scaleManifest,awsCodeBuild,undoRolloutManifest,noop,upsertAsgScheduledActions,enableInstancesInDiscovery,deleteEntityTags,concourse,destroyService,findArtifactsFromResource,registerInstancesWithLoadBalancer,jenkins,rebootInstances,rollbackServerGroup,upsertServerGroupTags,captureSourceServerGroupCapacity,upsertPluginInfo,destroyJob,cloudOperation,bulkQuickPatch,deployManifest,scaleDownCluster,findImageFromTags,pipeline,upsertScalingPolicy,upsertProject,detachInstances,updateApplication,preconfiguredWebhook,createApplication,deleteDeliveryConfig,unmapLoadBalancers,terminateInstanceAndDecrementAsg,modifyAwsScalingProcess,rollingPush,shareService,enableServerGroup,disableServerGroup,savePipelinesFromArtifact,webhook,deleteLoadBalancer,createServiceKey,resizeServerGroup,waitUntil,patchManifest,deploy,deleteManifest,lambdaFunction,upsertAmazonLoadBalancer,evaluateVariables,determineTargetServerGroup,updateJobProcesses,deleteImage,enableManifest,setPreferredPluginRelease,jira,deleteSecurityGroup,upsertAsgTags,enableAsg,wercker,waitForCondition,deleteProject,updateLaunchTemplate,preconfiguredJob,copySecurityGroup,mapLoadBalancers,restrictExecutionDuringTimeWindow,loadPluginRelease,terminateInstances,savePipeline,pauseRolloutManifest,startAppEngineServerGroup,dependsOnExecution,upsertTencentCloudScheduledActions,updateSecurityGroupsForServerGroup,modifyScalingProcess,upsertApplication,applySourceServerGroupCapacity,updateLaunchConfig,findArtifactFromExecution,bakeManifest,upsertAppEngineLoadBalancers,stopAppEngineServerGroup,copyLastAsg,pinServerGroup,upsertImageTags,deleteApplication,modifyScalingGroup,cloudFoundryCreateServiceBindings,rollingRestartManifest,bulkDestroyServerGroup,disableAsg,modifyAsg,unshareService,pageApplicationOwner,createServerGroup,deleteAmazonLoadBalancer,deleteScalingPolicy,bake,travis,destroyServerGroup,deleteServiceKey,deployAppEngineConfiguration) at com.netflix.spinnaker.orca.DefaultStageResolver.getStageDefinitionBuilder(DefaultStageResolver.java:75) at com.netflix.spinnaker.orca.pipeline.util.StageNavigator.lambda$ancestors$0(StageNavigator.java:51) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) at java.base/java.util.Collections$2.tryAdvance(Collections.java:4747) at java.base/java.util.Collections$2.forEachRemaining(Collections.java:4755) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at com.netflix.spinnaker.orca.pipeline.util.StageNavigator.ancestors(StageNavigator.java:53) at com.netflix.spinnaker.orca.q.handler.AuthenticationAware$DefaultImpls.withAuth(AuthenticationAware.kt:32) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withAuth(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler$handle$1.invoke(CompleteStageHandler.kt:119) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler$handle$1.invoke(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$withStage$1.invoke(OrcaMessageHandler.kt:85) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$withStage$1.invoke(OrcaMessageHandler.kt:46) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.withExecution(OrcaMessageHandler.kt:95) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withExecution(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.withStage(OrcaMessageHandler.kt:74) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.withStage(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.handle(CompleteStageHandler.kt:85) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.handle(CompleteStageHandler.kt:72) at com.netflix.spinnaker.q.MessageHandler$DefaultImpls.invoke(MessageHandler.kt:36) at com.netflix.spinnaker.orca.q.handler.OrcaMessageHandler$DefaultImpls.invoke(OrcaMessageHandler.kt) at com.netflix.spinnaker.orca.q.handler.CompleteStageHandler.invoke(CompleteStageHandler.kt:72) at com.netflix.spinnaker.orca.q.audit.ExecutionTrackingMessageHandlerPostProcessor$ExecutionTrackingMessageHandlerProxy.invoke(ExecutionTrackingMessageHandlerPostProcessor.kt:72) at com.netflix.spinnaker.q.QueueProcessor$callback$1$1.run(QueueProcessor.kt:90) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) ] exceptionType:NoSuchStageDefinitionBuilderException operation:createV2PipelineTemplate:ConstructAfterStages shouldRetry:false timestamp:1.652552232204e+12]] map[key:beforeStagePlanningFailed value:true]]]
Bạn kiểm tra bạn đã enable template hay chưa?
hal config features edit --pipeline-templates true
Sau đó mình đã chạy thành công




3) Design pipeline spinnaker through json file.
Bước tiếp theo chúng ta tạo 1 pipeline để tải sử dụng template trên
reference links:
https://spinnaker.io/guides/spin/app/
spin application save --application-name my-app --owner-email someone@example.com --cloud-providers "kubernetes" --config config-nimtechnology
3.1) Pipeline is created UI but it base on template.
Bằng UI spinnaker:




Bạn điền tên workload và kind của workload




Với cách run bằng UI thì chắc chắn là kho làm automation vậy chúng ta cần làm như sau:

3.2) Create Pipeline via Json file and Run pipeline through command.


sau đó bạn tạo 1 file json và paste nối dụng vào

Nếu bạn chạy câu lệnh
spin pi save --file pipeline-spin-nimtechnology.json --config config-nimtechnology
thi bạn sẽ bị báo lỗi
Required pipeline key 'name' missing... Required pipeline key 'application' missing... Submitted pipeline is invalid: map[exclude:[] keepWaitingPipelines:%!s(bool=false) lastModifiedBy:anonymous limitConcurrent:%!s(bool=true) notifications:[] parameterConfig:[] schema:v2 stages:[] template:map[artifactAccount:front50ArtifactCredentials reference:spinnaker://nimtSpinnakerTemplateV1 type:front50/pipelineTemplate] triggers:[] type:templatedPipeline updateTs:1652627797000 variables:map[kind:deployment workloadName:default-nimtechnology]]
Vì là trong json chưa có tên pipeline và pipeline trên thuộc application nào?

{
"name": "pipeline-is-created-by-command",
"application": "my-app",
"exclude": [],
"keepWaitingPipelines": false,
"lastModifiedBy": "anonymous",
"limitConcurrent": true,
"notifications": [],
"parameterConfig": [],
"schema": "v2",
"stages": [],
"template": {
"artifactAccount": "front50ArtifactCredentials",
"reference": "spinnaker://nimtSpinnakerTemplateV1",
"type": "front50/pipelineTemplate"
},
"triggers": [],
"type": "templatedPipeline",
"updateTs": "1652627797000",
"variables": {
"kind": "deployment",
"workloadName": "default-nimtechnology"
}
}

spin pipeline execute --name pipeline-is-created-by-command --application my-app


4) A few special Case
Mình cũng đã có migrate 1 số template cúa spinnaker sang template mình xin tổng hợp thêm một số trường hợp sau:
4.1) expectedArtifacts
Ơ các ví dụ trên thì chắc chắn là bạn chưa thấy mình lưu ý key này

{
"appConfig": {},
"expectedArtifacts": [
{
"defaultArtifact": {
"customKind": true,
"id": "c3e4adf6-9f9f-418f-b1af-2a4de93d792f"
},
"displayName": "docker-talaria",
"id": "834eae41-e13b-49ca-95d6-9801a587a85a",
"matchArtifact": {
"artifactAccount": "docker-registry",
"id": "78cf7ac2-a881-4ff7-b4a3-68eda1a271c6",
"name": "asia.gcr.io//talaria",
"type": "docker/image"
},
"useDefaultArtifact": false,
"usePriorArtifact": false
}
],
"keepWaitingPipelines": false,
"lastModifiedBy": "uc.dang@.vn",
"limitConcurrent": true,
"notifications": [
{
"address": "-build",
"level": "pipeline",
"message": {
"pipeline.failed": {
"text": "<@UHGA1UJ1F>"
}
},
"type": "slack",
"when": [
"pipeline.failed"
]
}
],
"parameterConfig": [
{
"default": "none",
"description": "",
"hasOptions": false,
"label": "type",
"name": "type",
"options": [
{
"value": "none"
},
{
"value": ""
}
],
"pinned": false,
"required": false
},
{
"default": "false",
"description": "",
"hasOptions": true,
"label": "",
"name": "dryRun",
"options": [
{
"value": "false"
},
{
"value": "true"
}
],
"pinned": false,
"required": false
}
],
"roles": [
"devops-admin"
],
"stages": [
{
"expectedArtifacts": [
{
"defaultArtifact": {
"customKind": true,
"id": "396d49b8-78c3-4f2a-92fe-5ca2a1f78081"
},
"displayName": "talaria-apiv2-helm-canary",
"id": "52638c19-89cc-4067-87a1-7b0f0c3eb621",
"matchArtifact": {
"id": "fd0fd41b-ecd1-4307-802d-2a06c61a9a56",
"name": "talaria-apiv2-canary",
"type": "embedded/base64"
},
"useDefaultArtifact": false,
"usePriorArtifact": false
}
Vậy lúc này bạn tạo ra 1 expectedArtifacts và nó nằm trong pipeline

"description": "Deploy image",
"name": "dockerRepo"
}
],
"id": "generic-v2",
"protect": false,
"metadata": {
"name": "Generic v2",
"description": "A generic template for basic use cases. No trigger configured",
"owner": "khai.phan@nimtechnology.vn",
"scopes": ["global"]
},
"pipeline": {
"application": "test",
"expectedArtifacts": [ #you can paste the content of expectedArtifacts at here
{
"defaultArtifact": {
"artifactAccount": "jenkins-artifacts",
"id": "67432764-b5aa-4392-948d-88920fa2e295",
"name": "gs://nimtechnology-prod-cicd-b20d-jenkins-artifacts/${ templateVariables.projectName }--values-${ templateVariables.profile }",
"reference": "gs://nimtechnology-prod-cicd-b20d-jenkins-artifacts/${ templateVariables.projectName }--values-${ templateVariables.profile }",
"type": "gcs/object"
},
"displayName": "${ templateVariables.projectName }--values-${ templateVariables.profile }",
"id": "8732f548-dfb4-4f52-9e2d-a52ff1c94a8a",
"matchArtifact": {
"artifactAccount": "jenkins-artifacts",
"id": "515a0e61-57a8-4973-8ded-e53d5464d58b",
"name": "gs://nimtechnology-prod-cicd-b20d-jenkins-artifacts/${ templateVariables.projectName }--values-${ templateVariables.profile }",
"type": "gcs/object"
},
"useDefaultArtifact": true,
"usePriorArtifact": false
},
{
"defaultArtifact": {