mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
add deployment demo
This commit is contained in:
@@ -222,9 +222,9 @@ type RolloutStatus struct {
|
||||
// Conditions represents the latest available observations of a CloneSet's current state.
|
||||
runtimev1alpha1.ConditionedStatus `json:",inline"`
|
||||
|
||||
// RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification
|
||||
// RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification
|
||||
// and does not change until the rollout is restarted
|
||||
RolloutTargetSize int32 `json:"rolloutTargetSize,omitempty"`
|
||||
RolloutTargetTotalSize int32 `json:"rolloutTargetSize,omitempty"`
|
||||
|
||||
// NewPodTemplateIdentifier is a string that uniquely represent the new pod template
|
||||
// each workload type could use different ways to identify that so we cannot compare between resources
|
||||
|
||||
@@ -180,7 +180,7 @@ func (r *RolloutStatus) RolloutFailing(reason string) {
|
||||
// ResetStatus resets the status of the rollout to start from beginning
|
||||
func (r *RolloutStatus) ResetStatus() {
|
||||
r.NewPodTemplateIdentifier = ""
|
||||
r.RolloutTargetSize = -1
|
||||
r.RolloutTargetTotalSize = -1
|
||||
r.LastAppliedPodTemplateIdentifier = ""
|
||||
r.RollingState = VerifyingSpecState
|
||||
r.BatchRollingState = BatchInitializingState
|
||||
|
||||
@@ -373,7 +373,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
services:
|
||||
|
||||
@@ -321,7 +321,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
targetGeneration:
|
||||
|
||||
@@ -342,7 +342,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
targetGeneration:
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Rollout Example
|
||||
Here is an example of how to rollout an application with a component of type deployment.
|
||||
|
||||
|
||||
## Rollout steps
|
||||
1. Install deployment based workloadDefinition
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/webservice-definition.yaml
|
||||
```
|
||||
|
||||
2. Apply an application
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-source.yaml
|
||||
```
|
||||
Wait for the application's status to be "running"
|
||||
|
||||
3. Prepare the application for rolling out
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-source-prep.yaml
|
||||
```
|
||||
Wait for the applicationConfiguration "test-rolling-v1" `Rolling Status` to be "RollingTemplated"
|
||||
|
||||
4. Modify the application image and apply
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-target.yaml
|
||||
```
|
||||
Wait for the applicationConfiguration "test-rolling-v2" `Rolling Status` to be "RollingTemplated"
|
||||
|
||||
5. Mark the application as normal
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-target-done.yaml
|
||||
```
|
||||
|
||||
6. Apply the application deployment with pause
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-deploy-pause.yaml
|
||||
```
|
||||
Check the status of the ApplicationDeployment and see the step by step rolling out.
|
||||
This rollout will pause after the second batch.
|
||||
|
||||
7. Apply the application deployment that completes the rollout
|
||||
```shell
|
||||
kubectl apply -f docs/examples/deployment-rollout/app-deploy-finish.yaml
|
||||
```
|
||||
Check the status of the ApplicationDeployment and see the rollout completes, and the
|
||||
applicationDeployment's "Rolling State" becomes `rolloutSucceed`
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: AppRollout
|
||||
metadata:
|
||||
name: rolling-test
|
||||
spec:
|
||||
# application (revision) reference
|
||||
targetAppRevisionName: test-rolling-v2
|
||||
sourceAppRevisionName: test-rolling-v1
|
||||
# HPA reference (optional)
|
||||
componentList:
|
||||
- metrics-provider
|
||||
rolloutPlan:
|
||||
rolloutStrategy: "IncreaseFirst"
|
||||
rolloutBatches:
|
||||
- replicas: 10%
|
||||
- replicas: 2
|
||||
- replicas: 2
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: AppRollout
|
||||
metadata:
|
||||
name: rolling-test
|
||||
spec:
|
||||
# application (revision) reference
|
||||
targetAppRevisionName: test-rolling-v2
|
||||
sourceAppRevisionName: test-rolling-v1
|
||||
# HPA reference (optional)
|
||||
componentList:
|
||||
- metrics-provider
|
||||
rolloutPlan:
|
||||
rolloutStrategy: "IncreaseFirst"
|
||||
rolloutBatches:
|
||||
- replicas: 10%
|
||||
- replicas: 2
|
||||
- replicas: 2
|
||||
batchPartition: 1
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: AppRollout
|
||||
metadata:
|
||||
name: rolling-test
|
||||
spec:
|
||||
# application (revision) reference
|
||||
targetAppRevisionName: test-rolling-v3
|
||||
sourceAppRevisionName: test-rolling-v2
|
||||
# HPA reference (optional)
|
||||
componentList:
|
||||
- metrics-provider
|
||||
rolloutPlan:
|
||||
rolloutStrategy: "IncreaseFirst"
|
||||
rolloutBatches:
|
||||
- replicas: 20%
|
||||
- replicas: 30%
|
||||
- replicas: 50%
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-rolling
|
||||
annotations:
|
||||
"app.oam.dev/rolling-components": "metrics-provider"
|
||||
"app.oam.dev/rollout-template": "true"
|
||||
spec:
|
||||
components:
|
||||
- name: metrics-provider
|
||||
type: webservice
|
||||
settings:
|
||||
cmd:
|
||||
- ./podinfo
|
||||
- stress-cpu=1
|
||||
image: stefanprodan/podinfo:4.0.6
|
||||
port: 8080
|
||||
updateStrategyType: InPlaceIfPossible
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-rolling
|
||||
spec:
|
||||
components:
|
||||
- name: metrics-provider
|
||||
type: webservice
|
||||
settings:
|
||||
cmd:
|
||||
- ./podinfo
|
||||
- stress-cpu=1
|
||||
image: stefanprodan/podinfo:4.0.6
|
||||
port: 8080
|
||||
updateStrategyType: InPlaceIfPossible
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-rolling
|
||||
spec:
|
||||
components:
|
||||
- name: metrics-provider
|
||||
type: webservice
|
||||
settings:
|
||||
cmd:
|
||||
- ./podinfo
|
||||
- stress-cpu=1
|
||||
image: stefanprodan/podinfo:5.0.2
|
||||
port: 8080
|
||||
updateStrategyType: InPlaceIfPossible
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-rolling
|
||||
annotations:
|
||||
"app.oam.dev/rolling-components": "metrics-provider"
|
||||
"app.oam.dev/rollout-template": "true"
|
||||
spec:
|
||||
components:
|
||||
- name: metrics-provider
|
||||
type: webservice
|
||||
settings:
|
||||
cmd:
|
||||
- ./podinfo
|
||||
- stress-cpu=1
|
||||
image: stefanprodan/podinfo:5.0.2
|
||||
port: 8080
|
||||
updateStrategyType: InPlaceIfPossible
|
||||
@@ -0,0 +1,94 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT.
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: WorkloadDefinition
|
||||
metadata:
|
||||
name: webservice
|
||||
annotations:
|
||||
definition.oam.dev/description: "Describes long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers."
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
replicas: parameter.replicas
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits:
|
||||
cpu: parameter.cpu
|
||||
requests:
|
||||
cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Which port do you want customer traffic sent to
|
||||
// +short=p
|
||||
port: *80 | int
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
// +usage=Number of pods in the deployment
|
||||
replicas: *5 | int
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
services:
|
||||
|
||||
@@ -321,7 +321,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
targetGeneration:
|
||||
|
||||
@@ -342,7 +342,7 @@ spec:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
rolloutTargetSize:
|
||||
description: RolloutTargetSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
description: RolloutTargetTotalSize is the size of the target resources. This is determined once the initial spec verification and does not change until the rollout is restarted
|
||||
format: int32
|
||||
type: integer
|
||||
targetGeneration:
|
||||
|
||||
@@ -75,7 +75,7 @@ func (r *Controller) Reconcile(ctx context.Context) (res reconcile.Result, statu
|
||||
defer func() {
|
||||
klog.InfoS("Finished one round of reconciling rollout plan", "rollout state", status.RollingState,
|
||||
"batch rolling state", status.BatchRollingState, "current batch", status.CurrentBatch,
|
||||
"upgraded Replicas", status.UpgradedReplicas, "ready Replicas", r.rolloutStatus.UpgradedReadyReplicas,
|
||||
"upgraded Replicas", status.UpgradedReplicas, "ready Replicas", status.UpgradedReadyReplicas,
|
||||
"reconcile result ", res)
|
||||
}()
|
||||
status = r.rolloutStatus
|
||||
@@ -128,7 +128,7 @@ func (r *Controller) Reconcile(ctx context.Context) (res reconcile.Result, statu
|
||||
}
|
||||
|
||||
case v1alpha1.FinalisingState:
|
||||
if succeed := workloadController.Finalize(ctx, false); succeed {
|
||||
if succeed := workloadController.Finalize(ctx, true); succeed {
|
||||
r.finalizeRollout(ctx)
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ func (r *Controller) reconcileBatchInRolling(ctx context.Context, workloadContro
|
||||
}
|
||||
|
||||
// makes sure that the current batch and replica count in the status are validate
|
||||
err := r.validateRollingBatchStatus(int(r.rolloutStatus.RolloutTargetSize))
|
||||
err := r.validateRollingBatchStatus(int(r.rolloutStatus.RolloutTargetTotalSize))
|
||||
if err != nil {
|
||||
r.rolloutStatus.RolloutFailing(err.Error())
|
||||
return
|
||||
@@ -374,8 +374,8 @@ func (r *Controller) GetWorkloadController() (workloads.WorkloadController, erro
|
||||
}
|
||||
var source types.NamespacedName
|
||||
if r.sourceWorkload != nil {
|
||||
source.Namespace = r.targetWorkload.GetNamespace()
|
||||
source.Name = r.targetWorkload.GetName()
|
||||
source.Namespace = r.sourceWorkload.GetNamespace()
|
||||
source.Name = r.sourceWorkload.GetName()
|
||||
}
|
||||
|
||||
if r.targetWorkload.GroupVersionKind().Group == kruisev1.GroupVersion.Group {
|
||||
|
||||
@@ -63,7 +63,7 @@ func (c *CloneSetController) VerifySpec(ctx context.Context) (bool, error) {
|
||||
}
|
||||
// record the size
|
||||
klog.InfoS("record the target size", "total replicas", totalReplicas)
|
||||
c.rolloutStatus.RolloutTargetSize = totalReplicas
|
||||
c.rolloutStatus.RolloutTargetTotalSize = totalReplicas
|
||||
|
||||
// make sure that the updateRevision is different from what we have already done
|
||||
targetHash := c.cloneSet.Status.UpdateRevision
|
||||
@@ -103,6 +103,13 @@ func (c *CloneSetController) Initialize(ctx context.Context) (bool, error) {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if controller := metav1.GetControllerOf(c.cloneSet); controller != nil {
|
||||
if controller.Kind == v1alpha2.AppRolloutKind && controller.APIVersion == v1alpha2.SchemeGroupVersion.String() {
|
||||
// it's already there
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
// add the parent controller to the owner of the cloneset
|
||||
// before kicking start the update and start from every pod in the old version
|
||||
clonePatch := client.MergeFrom(c.cloneSet.DeepCopyObject())
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
// DeploymentController is responsible for handle rollout deployment type of workloads
|
||||
// DeploymentController is responsible for handling rollout deployment type of workloads
|
||||
type DeploymentController struct {
|
||||
client client.Client
|
||||
recorder event.Recorder
|
||||
@@ -35,7 +35,7 @@ type DeploymentController struct {
|
||||
targetDeploy apps.Deployment
|
||||
}
|
||||
|
||||
// NewDeploymentController creates a new Deployment rollout controller
|
||||
// NewDeploymentController creates a new deployment rollout controller
|
||||
func NewDeploymentController(client client.Client, recorder event.Recorder, parentController oam.Object,
|
||||
rolloutSpec *v1alpha1.RolloutPlan, rolloutStatus *v1alpha1.RolloutStatus, sourceNamespacedName,
|
||||
targetNamespacedName types.NamespacedName) *DeploymentController {
|
||||
@@ -62,7 +62,7 @@ func (c *DeploymentController) VerifySpec(ctx context.Context) (bool, error) {
|
||||
}()
|
||||
|
||||
// check if the rollout spec is compatible with the current state
|
||||
totalReplicas, verifyErr := c.calculateTargetSize(ctx)
|
||||
targetTotalReplicas, verifyErr := c.calculateTargetTotalSize(ctx)
|
||||
if verifyErr != nil {
|
||||
// do not fail the rollout just because we can't get the resource
|
||||
c.rolloutStatus.RolloutRetry(verifyErr.Error())
|
||||
@@ -70,7 +70,7 @@ func (c *DeploymentController) VerifySpec(ctx context.Context) (bool, error) {
|
||||
}
|
||||
// record the size and we will use this value to drive the rest of the batches
|
||||
// we do not handle scale case in this controller
|
||||
c.rolloutStatus.RolloutTargetSize = totalReplicas
|
||||
c.rolloutStatus.RolloutTargetTotalSize = targetTotalReplicas
|
||||
|
||||
// make sure that the updateRevision is different from what we have already done
|
||||
targetHash, verifyErr := utils.ComputeSpecHash(c.targetDeploy.Spec)
|
||||
@@ -87,12 +87,17 @@ func (c *DeploymentController) VerifySpec(ctx context.Context) (bool, error) {
|
||||
|
||||
// check if the rollout batch replicas added up to the Deployment replicas
|
||||
// we don't handle scale case in this controller
|
||||
if verifyErr = c.verifyRolloutBatchReplicaValue(totalReplicas); verifyErr != nil {
|
||||
if verifyErr = c.verifyRolloutBatchReplicaValue(targetTotalReplicas); verifyErr != nil {
|
||||
return false, verifyErr
|
||||
}
|
||||
|
||||
if !c.sourceDeploy.Spec.Paused {
|
||||
return false, fmt.Errorf("the source eployment %s is still being reconciled, need to be paused",
|
||||
c.sourceDeploy.GetName())
|
||||
}
|
||||
|
||||
if !c.targetDeploy.Spec.Paused && c.targetDeploy.Spec.Replicas != pointer.Int32Ptr(0) {
|
||||
return false, fmt.Errorf("the Deployment %s is in the middle of updating, need to be paused or empty",
|
||||
return false, fmt.Errorf("the target deployment %s is not empty, need to be paused or empty",
|
||||
c.sourceDeploy.GetName())
|
||||
}
|
||||
|
||||
@@ -121,12 +126,12 @@ func (c *DeploymentController) Initialize(ctx context.Context) (bool, error) {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false, nil
|
||||
}
|
||||
err = c.claimDeployment(ctx, &c.sourceDeploy)
|
||||
err = c.claimDeployment(ctx, &c.sourceDeploy, false)
|
||||
if err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false, nil
|
||||
}
|
||||
err = c.claimDeployment(ctx, &c.targetDeploy)
|
||||
err = c.claimDeployment(ctx, &c.targetDeploy, c.calculateInitialTargetSize(ctx))
|
||||
if err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false, nil
|
||||
@@ -151,13 +156,13 @@ func (c *DeploymentController) RolloutOneBatchPods(ctx context.Context) (bool, e
|
||||
rolloutStrategy = c.rolloutSpec.RolloutStrategy
|
||||
}
|
||||
// Determine if we are the first or the second part of the current batch rollout
|
||||
if currentSizeSetting == c.rolloutStatus.RolloutTargetSize {
|
||||
if currentSizeSetting == c.rolloutStatus.RolloutTargetTotalSize {
|
||||
// we need to finish the first part of the rollout,
|
||||
// will always return false to not move to the next phase
|
||||
return false, c.rolloutBatchFirstHalf(ctx, rolloutStrategy)
|
||||
}
|
||||
// we are at the second half
|
||||
targetSize := c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetSize)
|
||||
targetSize := c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetTotalSize)
|
||||
if !c.rolloutBatchSecondHalf(ctx, rolloutStrategy, targetSize) {
|
||||
return false, nil
|
||||
}
|
||||
@@ -165,7 +170,7 @@ func (c *DeploymentController) RolloutOneBatchPods(ctx context.Context) (bool, e
|
||||
klog.InfoS("upgraded one batch", "current batch", c.rolloutStatus.CurrentBatch,
|
||||
"target deployment size", targetSize)
|
||||
c.recorder.Event(c.parentController, event.Normal("Batch Rollout",
|
||||
fmt.Sprintf("Submitted upgrade quest for batch %d", c.rolloutStatus.CurrentBatch)))
|
||||
fmt.Sprintf("Submitted upgrade quests for batch %d", c.rolloutStatus.CurrentBatch)))
|
||||
c.rolloutStatus.UpgradedReplicas = targetSize
|
||||
return true, nil
|
||||
}
|
||||
@@ -181,8 +186,8 @@ func (c *DeploymentController) CheckOneBatchPods(ctx context.Context) (bool, err
|
||||
readyTargetPodCount := c.targetDeploy.Status.ReadyReplicas
|
||||
sourcePodCount := c.sourceDeploy.Status.Replicas
|
||||
currentBatch := c.rolloutSpec.RolloutBatches[c.rolloutStatus.CurrentBatch]
|
||||
targetGoal := c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetSize)
|
||||
sourceGoal := c.calculateCurrentSource(c.rolloutStatus.RolloutTargetSize)
|
||||
targetGoal := c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetTotalSize)
|
||||
sourceGoal := c.calculateCurrentSource(c.rolloutStatus.RolloutTargetTotalSize)
|
||||
maxUnavail := 0
|
||||
if currentBatch.MaxUnavailable != nil {
|
||||
maxUnavail, _ = intstr.GetValueFromIntOrPercent(currentBatch.MaxUnavailable, int(targetGoal), true)
|
||||
@@ -194,7 +199,7 @@ func (c *DeploymentController) CheckOneBatchPods(ctx context.Context) (bool, err
|
||||
// make sure that the source deployment has the correct pods before moving the target
|
||||
// and the total we could overshoot in revert cases
|
||||
if sourcePodCount != sourceGoal ||
|
||||
int32(maxUnavail)+readyTargetPodCount+sourcePodCount < c.rolloutStatus.RolloutTargetSize {
|
||||
int32(maxUnavail)+readyTargetPodCount+sourcePodCount < c.rolloutStatus.RolloutTargetTotalSize {
|
||||
// continue to verify
|
||||
klog.InfoS("the batch is not ready yet", "current batch", c.rolloutStatus.CurrentBatch)
|
||||
c.rolloutStatus.RolloutRetry(fmt.Sprintf(
|
||||
@@ -214,12 +219,17 @@ func (c *DeploymentController) CheckOneBatchPods(ctx context.Context) (bool, err
|
||||
// FinalizeOneBatch makes sure that the rollout status are updated correctly
|
||||
func (c *DeploymentController) FinalizeOneBatch(ctx context.Context) (bool, error) {
|
||||
// nothing to do for Deployment for now
|
||||
return false, nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Finalize makes sure the Deployment is all upgraded
|
||||
func (c *DeploymentController) Finalize(ctx context.Context, succeed bool) bool {
|
||||
err := c.releaseDeployment(ctx, &c.sourceDeploy)
|
||||
err := c.fetchDeployments(ctx)
|
||||
if err != nil {
|
||||
// don't fail the rollout just because of we can't get the resource
|
||||
return false
|
||||
}
|
||||
err = c.releaseDeployment(ctx, &c.sourceDeploy)
|
||||
if err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false
|
||||
@@ -239,31 +249,36 @@ func (c *DeploymentController) Finalize(ctx context.Context, succeed bool) bool
|
||||
The functions below are helper functions
|
||||
--------------------- */
|
||||
|
||||
// calculateTargetSize fetches the Deployment and returns the replicas (not the actual number of pods)
|
||||
func (c *DeploymentController) calculateTargetSize(ctx context.Context) (int32, error) {
|
||||
// calculateTargetTotalSize fetches the Deployment and returns the replicas (not the actual number of pods)
|
||||
func (c *DeploymentController) calculateTargetTotalSize(ctx context.Context) (int32, error) {
|
||||
if err := c.fetchDeployments(ctx); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// the spec target size is the truth if it's set
|
||||
if c.rolloutSpec.TargetSize != nil {
|
||||
return *c.rolloutSpec.TargetSize, nil
|
||||
}
|
||||
// otherwise, we assume that the source is the total
|
||||
// source default is 1
|
||||
var sourceSize int32 = 1
|
||||
var targetSize int32 = 0
|
||||
if c.sourceDeploy.Spec.Replicas != nil {
|
||||
sourceSize = *c.sourceDeploy.Spec.Replicas
|
||||
}
|
||||
if c.targetDeploy.Spec.Replicas != nil {
|
||||
targetSize = *c.targetDeploy.Spec.Replicas
|
||||
return sourceSize, nil
|
||||
}
|
||||
|
||||
// calculateInitialTargetSize calculates what the initial replica should be set to the target deploy
|
||||
func (c *DeploymentController) calculateInitialTargetSize(ctx context.Context) bool {
|
||||
total, _ := c.calculateTargetTotalSize(ctx)
|
||||
var sourceSize int32 = 1
|
||||
if c.sourceDeploy.Spec.Replicas != nil {
|
||||
sourceSize = *c.sourceDeploy.Spec.Replicas
|
||||
}
|
||||
return sourceSize + targetSize, nil
|
||||
return total == sourceSize
|
||||
}
|
||||
|
||||
// check if the replicas in all the rollout batches add up to the right number
|
||||
func (c *DeploymentController) verifyRolloutBatchReplicaValue(totalReplicas int32) error {
|
||||
// the target size has to be the same as the Deployment size
|
||||
if c.rolloutSpec.TargetSize != nil && *c.rolloutSpec.TargetSize != totalReplicas {
|
||||
return fmt.Errorf("the rollout plan is attempting to scale the Deployment, target = %d, Deployment size = %d",
|
||||
*c.rolloutSpec.TargetSize, totalReplicas)
|
||||
}
|
||||
// use a common function to check if the sum of all the batches can match the Deployment size
|
||||
err := VerifySumOfBatchSizes(c.rolloutSpec, totalReplicas)
|
||||
if err != nil {
|
||||
@@ -294,13 +309,18 @@ func (c *DeploymentController) fetchDeployments(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// add the parent controller to the owner of the Deployment
|
||||
// add the parent controller to the owner of the deployment, unpause it and initialize the size
|
||||
// before kicking start the update and start from every pod in the old version
|
||||
func (c *DeploymentController) claimDeployment(ctx context.Context, deploy *apps.Deployment) error {
|
||||
func (c *DeploymentController) claimDeployment(ctx context.Context, deploy *apps.Deployment, initSize bool) error {
|
||||
deployPatch := client.MergeFrom(deploy.DeepCopyObject())
|
||||
ref := metav1.NewControllerRef(c.parentController, v1alpha2.AppRolloutKindVersionKind)
|
||||
deploy.SetOwnerReferences(append(deploy.GetOwnerReferences(), *ref))
|
||||
if controller := metav1.GetControllerOf(deploy); controller == nil {
|
||||
ref := metav1.NewControllerRef(c.parentController, v1alpha2.AppRolloutKindVersionKind)
|
||||
deploy.SetOwnerReferences(append(deploy.GetOwnerReferences(), *ref))
|
||||
}
|
||||
deploy.Spec.Paused = false
|
||||
if initSize {
|
||||
deploy.Spec.Replicas = pointer.Int32Ptr(0)
|
||||
}
|
||||
// patch the Deployment
|
||||
if err := c.client.Patch(ctx, deploy, deployPatch, client.FieldOwner(c.parentController.GetUID())); err != nil {
|
||||
c.recorder.Event(c.parentController, event.Warning("Failed to the start the Deployment update", err))
|
||||
@@ -313,7 +333,7 @@ func (c *DeploymentController) rolloutBatchFirstHalf(ctx context.Context, rollou
|
||||
var err error
|
||||
if rolloutStrategy == v1alpha1.IncreaseFirstRolloutStrategyType {
|
||||
// set the target replica first which should increase its size
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetSize),
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentTarget(c.rolloutStatus.RolloutTargetTotalSize),
|
||||
&c.targetDeploy); err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
}
|
||||
@@ -321,7 +341,7 @@ func (c *DeploymentController) rolloutBatchFirstHalf(ctx context.Context, rollou
|
||||
}
|
||||
if rolloutStrategy == v1alpha1.DecreaseFirstRolloutStrategyType {
|
||||
// set the source replicas first which should shrink its size
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentSource(c.rolloutStatus.RolloutTargetSize),
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentSource(c.rolloutStatus.RolloutTargetTotalSize),
|
||||
&c.sourceDeploy); err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
}
|
||||
@@ -343,7 +363,7 @@ func (c *DeploymentController) rolloutBatchSecondHalf(ctx context.Context,
|
||||
// make sure that the target deployment has enough ready pods before reducing the source
|
||||
if c.targetDeploy.Status.ReadyReplicas+int32(maxUnavail) >= targetSize {
|
||||
// set the source replicas now which should shrink its size
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentSource(c.rolloutStatus.RolloutTargetSize),
|
||||
if err = c.patchDeployment(ctx, c.calculateCurrentSource(c.rolloutStatus.RolloutTargetTotalSize),
|
||||
&c.sourceDeploy); err != nil {
|
||||
c.rolloutStatus.RolloutRetry(err.Error())
|
||||
return false
|
||||
@@ -358,7 +378,7 @@ func (c *DeploymentController) rolloutBatchSecondHalf(ctx context.Context,
|
||||
}
|
||||
} else if rolloutStrategy == v1alpha1.DecreaseFirstRolloutStrategyType {
|
||||
// make sure that the source deployment has the correct pods before moving the target
|
||||
sourceSize := c.calculateCurrentSource(c.rolloutStatus.RolloutTargetSize)
|
||||
sourceSize := c.calculateCurrentSource(c.rolloutStatus.RolloutTargetTotalSize)
|
||||
if c.sourceDeploy.Status.Replicas == sourceSize {
|
||||
// we can increase the target deployment as soon as the source deployment's replica is correct
|
||||
// no need to wait for them to be ready
|
||||
@@ -402,18 +422,10 @@ func (c *DeploymentController) calculateCurrentTarget(totalSize int32) int32 {
|
||||
return targetSize
|
||||
}
|
||||
|
||||
// the target deploy size for the current batch
|
||||
// the source deploy size for the current batch
|
||||
func (c *DeploymentController) calculateCurrentSource(totalSize int32) int32 {
|
||||
currentBatch := int(c.rolloutStatus.CurrentBatch)
|
||||
var sourceSize int32
|
||||
for i, r := range c.rolloutSpec.RolloutBatches {
|
||||
batchSize, _ := intstr.GetValueFromIntOrPercent(&r.Replicas, int(totalSize), true)
|
||||
if i < currentBatch {
|
||||
sourceSize += int32(batchSize)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
sourceSize := totalSize - c.calculateCurrentTarget(totalSize)
|
||||
klog.InfoS("Calculated the number of pods in the source deployment after current batch",
|
||||
"current batch", currentBatch, "source deploy size", sourceSize)
|
||||
return sourceSize
|
||||
@@ -429,9 +441,8 @@ func (c *DeploymentController) patchDeployment(ctx context.Context, target int32
|
||||
"Failed to update the deployment %s to the correct target %d", deploy.GetName(), target)), err))
|
||||
return err
|
||||
}
|
||||
c.recorder.Event(c.parentController, event.Normal("Batch Rollout",
|
||||
fmt.Sprintf("Submitted upgrade quest for deployment %s to have %d pods for batch %d",
|
||||
deploy.GetName(), target, c.rolloutStatus.CurrentBatch)))
|
||||
klog.InfoS("Submitted upgrade quest for deployment", "deployment",
|
||||
deploy.GetName(), "target replica size", target, "batch", c.rolloutStatus.CurrentBatch)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+10
-3
@@ -15,6 +15,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
@@ -75,9 +76,15 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, env
|
||||
}
|
||||
|
||||
var message = ""
|
||||
// Create Namespace
|
||||
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return message, err
|
||||
// Check If Namespace Exists
|
||||
if err := c.Get(ctx, k8stypes.NamespacedName{Name: envArgs.Namespace}, &corev1.Namespace{}); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return message, err
|
||||
}
|
||||
// Create Namespace if not found
|
||||
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil {
|
||||
return message, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create Issuer For SSL if both email and domain are all set.
|
||||
|
||||
@@ -199,8 +199,8 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*240, time.Second).Should(Equal(oamstd.RolloutSucceedState))
|
||||
Expect(appRollout.Status.UpgradedReadyReplicas).Should(BeEquivalentTo(appRollout.Status.RolloutTargetSize))
|
||||
Expect(appRollout.Status.UpgradedReplicas).Should(BeEquivalentTo(appRollout.Status.RolloutTargetSize))
|
||||
Expect(appRollout.Status.UpgradedReadyReplicas).Should(BeEquivalentTo(appRollout.Status.RolloutTargetTotalSize))
|
||||
Expect(appRollout.Status.UpgradedReplicas).Should(BeEquivalentTo(appRollout.Status.RolloutTargetTotalSize))
|
||||
}
|
||||
|
||||
VerifyAppConfigRollingCompleted := func(appConfigName string) {
|
||||
|
||||
Reference in New Issue
Block a user