Skip to content

Commit

Permalink
Support Kubernetes RollingUpdate configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Sgitario committed Jun 23, 2023
1 parent 6c169af commit 7283117
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import io.dekorate.kubernetes.annotation.ImagePullPolicy;
import io.dekorate.kubernetes.annotation.ServiceType;
import io.dekorate.kubernetes.config.DeploymentStrategy;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.kubernetes.spi.DeployStrategy;
Expand Down Expand Up @@ -128,6 +129,20 @@ public enum DeploymentResourceKind {
@ConfigItem(defaultValue = "1")
Integer replicas;

/**
* Specifies the deployment strategy.
*/
@ConfigItem(defaultValue = "None")
DeploymentStrategy strategy;

/**
* Specifies rolling update configuration.
* The configuration is applied when DeploymentStrategy == RollingUpdate, or
* when explicit configuration has been provided. In the later case RollingUpdate is assumed.
*/
@ConfigItem
RollingUpdateConfig rollingUpdate;

/**
* The type of service that will be generated for the application
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.quarkus.kubernetes.deployment;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;

@ConfigGroup
public class RollingUpdateConfig {
/**
* Specifies the maximum number of Pods that can be unavailable during the update process.
*/
@ConfigItem(defaultValue = "25%")
String maxUnavailable;

/**
* Specifies the maximum number of Pods that can be created over the desired number of Pods.
*/
@ConfigItem(defaultValue = "25%")
String maxSurge;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@
import java.util.stream.Stream;

import io.dekorate.kubernetes.annotation.ServiceType;
import io.dekorate.kubernetes.config.DeploymentStrategy;
import io.dekorate.kubernetes.config.EnvBuilder;
import io.dekorate.kubernetes.config.IngressBuilder;
import io.dekorate.kubernetes.config.IngressRuleBuilder;
import io.dekorate.kubernetes.config.Port;
import io.dekorate.kubernetes.config.RollingUpdateBuilder;
import io.dekorate.kubernetes.decorator.AddAnnotationDecorator;
import io.dekorate.kubernetes.decorator.AddEnvVarDecorator;
import io.dekorate.kubernetes.decorator.AddIngressRuleDecorator;
import io.dekorate.kubernetes.decorator.AddIngressTlsDecorator;
import io.dekorate.kubernetes.decorator.ApplicationContainerDecorator;
import io.dekorate.kubernetes.decorator.ApplyDeploymentStrategyDecorator;
import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator;
import io.dekorate.kubernetes.decorator.ApplyReplicasToDeploymentDecorator;
import io.dekorate.kubernetes.decorator.ApplyReplicasToStatefulSetDecorator;
Expand Down Expand Up @@ -287,6 +290,15 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
result.add(new DecoratorBuildItem(KUBERNETES, new RemovePortFromServiceDecorator(name, MANAGEMENT_PORT_NAME)));
}

// Handle deployment strategy
if (config.strategy != DeploymentStrategy.None) {
result.add(new DecoratorBuildItem(KUBERNETES,
new ApplyDeploymentStrategyDecorator(name, config.strategy, new RollingUpdateBuilder()
.withMaxSurge(config.rollingUpdate.maxSurge)
.withMaxUnavailable(config.rollingUpdate.maxUnavailable)
.build())));
}

return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public void assertGeneratedResources() throws IOException {
});
});
});
assertThat(deploymentSpec.getStrategy()).isNull();
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

package io.quarkus.it.kubernetes;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.quarkus.builder.Version;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class KubernetesWithStrategyRollingUpdateTest {

private static final String APP_NAME = "kubernetes-with-strategy-rolling-update";
private static final String STRATEGY_TYPE = "RollingUpdate";
private static final String MAX_UNAVAILABLE = "35%";
private static final String MAX_SURGE = "39%";

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class))
.setApplicationName(APP_NAME)
.setApplicationVersion("0.1-SNAPSHOT")
.overrideConfigKey("quarkus.kubernetes.strategy", STRATEGY_TYPE)
.overrideConfigKey("quarkus.kubernetes.rolling-update.max-unavailable", MAX_UNAVAILABLE)
.overrideConfigKey("quarkus.kubernetes.rolling-update.max-surge", MAX_SURGE)
.setForcedDependencies(List.of(Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion())));

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
public void assertGeneratedResources() throws IOException {
final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes");
assertThat(kubernetesDir)
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json"))
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml"));
List<HasMetadata> kubernetesList = DeserializationUtil
.deserializeAsList(kubernetesDir.resolve("kubernetes.yml"));

assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> {
assertThat(d.getMetadata()).satisfies(m -> {
assertThat(m.getName()).isEqualTo(APP_NAME);
});

assertThat(d.getSpec()).satisfies(spec -> {
assertThat(spec.getStrategy().getType()).isEqualTo(STRATEGY_TYPE);
assertThat(spec.getStrategy().getRollingUpdate()).isNotNull();
assertThat(spec.getStrategy().getRollingUpdate().getMaxUnavailable().getStrVal()).isEqualTo(MAX_UNAVAILABLE);
assertThat(spec.getStrategy().getRollingUpdate().getMaxSurge().getStrVal()).isEqualTo(MAX_SURGE);
});
});
}
}

0 comments on commit 7283117

Please sign in to comment.