mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-16 03:22:18 +08:00
Traffic split - canary deployment
This commit is contained in:
parent
634370ab70
commit
534896c172
@ -38,7 +38,6 @@ inputs:
|
|||||||
traffic-split-annotations:
|
traffic-split-annotations:
|
||||||
description: 'Traffic split annotations in the form of key/value pair can be used'
|
description: 'Traffic split annotations in the form of key/value pair can be used'
|
||||||
required: false
|
required: false
|
||||||
default: 0
|
|
||||||
baseline-and-canary-replicas:
|
baseline-and-canary-replicas:
|
||||||
description: 'Baseline and canary replicas count. Valid value between 0 to 100 (inclusive)'
|
description: 'Baseline and canary replicas count. Valid value between 0 to 100 (inclusive)'
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
@ -19,7 +19,8 @@ import {parseRouteStrategy} from '../types/routeStrategy'
|
|||||||
export async function deploy(
|
export async function deploy(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
manifestFilePaths: string[],
|
manifestFilePaths: string[],
|
||||||
deploymentStrategy: DeploymentStrategy
|
deploymentStrategy: DeploymentStrategy,
|
||||||
|
annotations: {[key: string]: string} = {}
|
||||||
) {
|
) {
|
||||||
// update manifests
|
// update manifests
|
||||||
const inputManifestFiles: string[] = updateManifestFiles(manifestFilePaths)
|
const inputManifestFiles: string[] = updateManifestFiles(manifestFilePaths)
|
||||||
@ -34,7 +35,8 @@ export async function deploy(
|
|||||||
inputManifestFiles,
|
inputManifestFiles,
|
||||||
deploymentStrategy,
|
deploymentStrategy,
|
||||||
kubectl,
|
kubectl,
|
||||||
trafficSplitMethod
|
trafficSplitMethod,
|
||||||
|
annotations
|
||||||
)
|
)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
core.debug('Deployed manifest files: ' + deployedManifestFiles)
|
core.debug('Deployed manifest files: ' + deployedManifestFiles)
|
||||||
@ -55,7 +57,7 @@ export async function deploy(
|
|||||||
const routeStrategy = parseRouteStrategy(
|
const routeStrategy = parseRouteStrategy(
|
||||||
core.getInput('route-method', {required: true})
|
core.getInput('route-method', {required: true})
|
||||||
)
|
)
|
||||||
await routeBlueGreen(kubectl, inputManifestFiles, routeStrategy)
|
await routeBlueGreen(kubectl, inputManifestFiles, routeStrategy) //----
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/run.ts
25
src/run.ts
@ -6,6 +6,7 @@ import {reject} from './actions/reject'
|
|||||||
import {Action, parseAction} from './types/action'
|
import {Action, parseAction} from './types/action'
|
||||||
import {parseDeploymentStrategy} from './types/deploymentStrategy'
|
import {parseDeploymentStrategy} from './types/deploymentStrategy'
|
||||||
import {getFilesFromDirectories} from './utilities/fileUtils'
|
import {getFilesFromDirectories} from './utilities/fileUtils'
|
||||||
|
import {stringify} from 'querystring'
|
||||||
|
|
||||||
export async function run() {
|
export async function run() {
|
||||||
// verify kubeconfig is set
|
// verify kubeconfig is set
|
||||||
@ -18,7 +19,8 @@ export async function run() {
|
|||||||
const action: Action | undefined = parseAction(
|
const action: Action | undefined = parseAction(
|
||||||
core.getInput('action', {required: true})
|
core.getInput('action', {required: true})
|
||||||
)
|
)
|
||||||
const annotations: {[key: string]: string} = {}
|
const annotation: {[key: string]: string} = {}
|
||||||
|
const annotations = core.getInput(stringify(annotation), {required: true})
|
||||||
const strategy = parseDeploymentStrategy(core.getInput('strategy'))
|
const strategy = parseDeploymentStrategy(core.getInput('strategy'))
|
||||||
const manifestsInput = core.getInput('manifests', {required: true})
|
const manifestsInput = core.getInput('manifests', {required: true})
|
||||||
const manifestFilePaths = manifestsInput
|
const manifestFilePaths = manifestsInput
|
||||||
@ -35,15 +37,30 @@ export async function run() {
|
|||||||
// run action
|
// run action
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case Action.DEPLOY: {
|
case Action.DEPLOY: {
|
||||||
await deploy(kubectl, fullManifestFilePaths, strategy)
|
await deploy(
|
||||||
|
kubectl,
|
||||||
|
fullManifestFilePaths,
|
||||||
|
strategy,
|
||||||
|
JSON.parse(annotations)
|
||||||
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case Action.PROMOTE: {
|
case Action.PROMOTE: {
|
||||||
await promote(kubectl, fullManifestFilePaths, strategy, annotations)
|
await promote(
|
||||||
|
kubectl,
|
||||||
|
fullManifestFilePaths,
|
||||||
|
strategy,
|
||||||
|
JSON.parse(annotations)
|
||||||
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case Action.REJECT: {
|
case Action.REJECT: {
|
||||||
await reject(kubectl, fullManifestFilePaths, strategy, annotations)
|
await reject(
|
||||||
|
kubectl,
|
||||||
|
fullManifestFilePaths,
|
||||||
|
strategy,
|
||||||
|
JSON.parse(annotations)
|
||||||
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@ -23,7 +23,8 @@ const MAX_VAL = 100
|
|||||||
|
|
||||||
export async function deployBlueGreenSMI(
|
export async function deployBlueGreenSMI(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
filePaths: string[]
|
filePaths: string[],
|
||||||
|
annotations: {[key: string]: string} = {}
|
||||||
) {
|
) {
|
||||||
// get all kubernetes objects defined in manifest files
|
// get all kubernetes objects defined in manifest files
|
||||||
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
||||||
@ -37,7 +38,7 @@ export async function deployBlueGreenSMI(
|
|||||||
await kubectl.apply(manifestFiles)
|
await kubectl.apply(manifestFiles)
|
||||||
|
|
||||||
// make extraservices and trafficsplit
|
// make extraservices and trafficsplit
|
||||||
await setupSMI(kubectl, manifestObjects.serviceEntityList)
|
await setupSMI(kubectl, manifestObjects.serviceEntityList, annotations)
|
||||||
|
|
||||||
// create new deloyments
|
// create new deloyments
|
||||||
return await createWorkloadsWithLabel(
|
return await createWorkloadsWithLabel(
|
||||||
@ -93,7 +94,11 @@ export async function rejectBlueGreenSMI(
|
|||||||
await cleanupSMI(kubectl, manifestObjects.serviceEntityList)
|
await cleanupSMI(kubectl, manifestObjects.serviceEntityList)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupSMI(kubectl: Kubectl, serviceEntityList: any[]) {
|
export async function setupSMI(
|
||||||
|
kubectl: Kubectl,
|
||||||
|
serviceEntityList: any[],
|
||||||
|
annotaions: {[key: string]: string} = {}
|
||||||
|
) {
|
||||||
const newObjectsList = []
|
const newObjectsList = []
|
||||||
const trafficObjectList = []
|
const trafficObjectList = []
|
||||||
|
|
||||||
@ -119,7 +124,8 @@ export async function setupSMI(kubectl: Kubectl, serviceEntityList: any[]) {
|
|||||||
createTrafficSplitObject(
|
createTrafficSplitObject(
|
||||||
kubectl,
|
kubectl,
|
||||||
inputObject.metadata.name,
|
inputObject.metadata.name,
|
||||||
NONE_LABEL_VALUE
|
NONE_LABEL_VALUE,
|
||||||
|
annotaions
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,8 @@ export async function deployManifests(
|
|||||||
files: string[],
|
files: string[],
|
||||||
deploymentStrategy: DeploymentStrategy,
|
deploymentStrategy: DeploymentStrategy,
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
trafficSplitMethod: TrafficSplitMethod
|
trafficSplitMethod: TrafficSplitMethod,
|
||||||
|
annotaions: {[key: string]: string} = {}
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
switch (deploymentStrategy) {
|
switch (deploymentStrategy) {
|
||||||
case DeploymentStrategy.CANARY: {
|
case DeploymentStrategy.CANARY: {
|
||||||
@ -63,7 +64,7 @@ export async function deployManifests(
|
|||||||
(routeStrategy == RouteStrategy.INGRESS &&
|
(routeStrategy == RouteStrategy.INGRESS &&
|
||||||
deployBlueGreenIngress(kubectl, files)) ||
|
deployBlueGreenIngress(kubectl, files)) ||
|
||||||
(routeStrategy == RouteStrategy.SMI &&
|
(routeStrategy == RouteStrategy.SMI &&
|
||||||
deployBlueGreenSMI(kubectl, files)) ||
|
deployBlueGreenSMI(kubectl, files, annotaions)) ||
|
||||||
deployBlueGreenService(kubectl, files)
|
deployBlueGreenService(kubectl, files)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -289,15 +289,12 @@ describe('Kubectl class', () => {
|
|||||||
it('gets resource', async () => {
|
it('gets resource', async () => {
|
||||||
const resourceType = 'type'
|
const resourceType = 'type'
|
||||||
const name = 'name'
|
const name = 'name'
|
||||||
const annotations: {[key: string]: string} = {}
|
expect(await kubectl.getResource(resourceType, name)).toBe(execReturn)
|
||||||
expect(
|
|
||||||
await kubectl.getResource(resourceType, name, annotations)
|
|
||||||
).toBe(execReturn)
|
|
||||||
expect(exec.getExecOutput).toBeCalledWith(
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
kubectlPath,
|
kubectlPath,
|
||||||
[
|
[
|
||||||
'get',
|
'get',
|
||||||
`${resourceType}/${name}/${annotations}`,
|
`${resourceType}/${name}`,
|
||||||
'-o',
|
'-o',
|
||||||
'json',
|
'json',
|
||||||
'--namespace',
|
'--namespace',
|
||||||
|
|||||||
@ -135,12 +135,11 @@ export class Kubectl {
|
|||||||
|
|
||||||
public async getResource(
|
public async getResource(
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
name: string,
|
name: string
|
||||||
annotations: {[key: string]: string} = {}
|
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
return await this.execute([
|
return await this.execute([
|
||||||
'get',
|
'get',
|
||||||
`${resourceType}/${name}/${annotations}`,
|
`${resourceType}/${name}`,
|
||||||
'-o',
|
'-o',
|
||||||
'json'
|
'json'
|
||||||
])
|
])
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user