1.32 k8s开发
This commit is contained in:
parent
d5188bc94d
commit
a19b4b8ec8
@ -633,51 +633,82 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp
|
||||
|
||||
/**
|
||||
* 重启Deployment(通过更新annotation触发滚动更新)
|
||||
*
|
||||
* <p>实现原理:</p>
|
||||
* <ul>
|
||||
* <li>使用Strategic Merge Patch方式更新Deployment的Pod模板注解</li>
|
||||
* <li>添加/更新 kubectl.kubernetes.io/restartedAt 注解,值为当前时间戳</li>
|
||||
* <li>K8s检测到Pod模板变化后,会触发滚动更新(Rolling Update)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>安全性说明:</p>
|
||||
* <ul>
|
||||
* <li><b>Strategic Merge Patch是合并式操作</b>:只更新指定字段,不会影响其他配置</li>
|
||||
* <li><b>不会覆盖原有内容</b>:对于annotations这种map类型,会合并新的key-value,保留已有的annotations</li>
|
||||
* <li><b>K8s官方推荐方式</b>:kubectl rollout restart命令的底层实现就是这种方式</li>
|
||||
* <li><b>原有YAML配置完全保留</b>:包括labels、环境变量、资源限制、挂载卷等所有配置</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>等价于执行命令:kubectl rollout restart deployment/{deploymentName} -n {namespace}</p>
|
||||
*/
|
||||
@Override
|
||||
public void restartDeployment(ExternalSystem externalSystem, String namespace, String deploymentName) {
|
||||
log.info("重启K8S Deployment,集群: {}, 命名空间: {}, Deployment: {}",
|
||||
log.info("开始重启K8S Deployment,集群: {}, 命名空间: {}, Deployment: {}",
|
||||
externalSystem.getName(), namespace, deploymentName);
|
||||
|
||||
try {
|
||||
K8sApiClientCache cache = getApiClientCache(externalSystem);
|
||||
AppsV1Api api = new AppsV1Api(cache.apiClient);
|
||||
|
||||
// 构建patch内容:更新spec.template.metadata.annotations添加重启时间戳
|
||||
// 使用ISO 8601格式的时间戳
|
||||
// 生成ISO 8601格式的时间戳作为重启标记
|
||||
String timestamp = java.time.format.DateTimeFormatter.ISO_INSTANT
|
||||
.format(java.time.Instant.now());
|
||||
|
||||
// 构建Strategic Merge Patch内容
|
||||
// 只更新 spec.template.metadata.annotations 中的 kubectl.kubernetes.io/restartedAt 字段
|
||||
// 其他所有字段(replicas、image、env、resources等)都不会受影响
|
||||
String patchBody = String.format(
|
||||
"{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"kubectl.kubernetes.io/restartedAt\":\"%s\"}}}}}",
|
||||
timestamp
|
||||
);
|
||||
|
||||
// 使用strategic merge patch更新Deployment
|
||||
api.patchNamespacedDeployment(
|
||||
deploymentName,
|
||||
namespace,
|
||||
new io.kubernetes.client.custom.V1Patch(patchBody),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
log.info("执行Strategic Merge Patch,Deployment: {}/{}, 重启时间戳: {}",
|
||||
namespace, deploymentName, timestamp);
|
||||
|
||||
// 使用PatchUtils进行strategic merge patch
|
||||
// Strategic Merge Patch会智能合并JSON,只更新指定的字段路径
|
||||
io.kubernetes.client.util.PatchUtils.patch(
|
||||
io.kubernetes.client.openapi.models.V1Deployment.class,
|
||||
() -> api.patchNamespacedDeploymentCall(
|
||||
deploymentName,
|
||||
namespace,
|
||||
new io.kubernetes.client.custom.V1Patch(patchBody),
|
||||
null, // pretty
|
||||
null, // dryRun
|
||||
null, // fieldManager
|
||||
null, // fieldValidation
|
||||
null, // force
|
||||
null // callback
|
||||
),
|
||||
io.kubernetes.client.custom.V1Patch.PATCH_FORMAT_STRATEGIC_MERGE_PATCH,
|
||||
api.getApiClient()
|
||||
);
|
||||
|
||||
log.info("重启K8S Deployment成功");
|
||||
log.info("重启K8S Deployment成功,集群: {}, 命名空间: {}, Deployment: {}, K8s将开始滚动更新Pod",
|
||||
externalSystem.getName(), namespace, deploymentName);
|
||||
|
||||
} catch (ApiException e) {
|
||||
if (e.getCode() == 404) {
|
||||
log.warn("Deployment不存在: {}/{}", namespace, deploymentName);
|
||||
log.warn("重启失败:Deployment不存在,集群: {}, 命名空间: {}, Deployment: {}",
|
||||
externalSystem.getName(), namespace, deploymentName);
|
||||
throw new BusinessException(ResponseCode.K8S_RESOURCE_NOT_FOUND);
|
||||
}
|
||||
log.error("重启K8S Deployment失败,集群: {}, 命名空间: {}, Deployment: {}, HTTP状态码: {}, 错误信息: {}, 响应体: {}",
|
||||
externalSystem.getName(), namespace, deploymentName, e.getCode(), e.getMessage(), e.getResponseBody(), e);
|
||||
throw new BusinessException(ResponseCode.K8S_OPERATION_FAILED);
|
||||
} catch (Exception e) {
|
||||
log.error("重启K8S Deployment失败,集群: {}, 命名空间: {}, Deployment: {}, 错误: {}",
|
||||
externalSystem.getName(), namespace, deploymentName, e.getMessage(), e);
|
||||
log.error("重启K8S Deployment失败(非K8s API异常),集群: {}, 命名空间: {}, Deployment: {}, 错误类型: {}, 错误信息: {}",
|
||||
externalSystem.getName(), namespace, deploymentName, e.getClass().getSimpleName(), e.getMessage(), e);
|
||||
throw new BusinessException(ResponseCode.K8S_OPERATION_FAILED);
|
||||
}
|
||||
}
|
||||
@ -697,16 +728,22 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp
|
||||
// 构建patch内容:更新spec.replicas
|
||||
String patchBody = String.format("{\"spec\":{\"replicas\":%d}}", replicas);
|
||||
|
||||
// 使用strategic merge patch更新Deployment的scale
|
||||
api.patchNamespacedDeploymentScale(
|
||||
deploymentName,
|
||||
namespace,
|
||||
new io.kubernetes.client.custom.V1Patch(patchBody),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
// 使用PatchUtils进行strategic merge patch,确保Content-Type正确
|
||||
io.kubernetes.client.util.PatchUtils.patch(
|
||||
io.kubernetes.client.openapi.models.V1Scale.class,
|
||||
() -> api.patchNamespacedDeploymentScaleCall(
|
||||
deploymentName,
|
||||
namespace,
|
||||
new io.kubernetes.client.custom.V1Patch(patchBody),
|
||||
null, // pretty
|
||||
null, // dryRun
|
||||
null, // fieldManager
|
||||
null, // fieldValidation
|
||||
null, // force
|
||||
null // callback
|
||||
),
|
||||
io.kubernetes.client.custom.V1Patch.PATCH_FORMAT_STRATEGIC_MERGE_PATCH,
|
||||
api.getApiClient()
|
||||
);
|
||||
|
||||
log.info("扩缩容K8S Deployment成功");
|
||||
|
||||
@ -191,9 +191,12 @@ public class K8sDeploymentServiceImpl extends BaseServiceImpl<K8sDeployment, K8s
|
||||
|
||||
int syncCount = (int) deploymentResponses.size();
|
||||
|
||||
log.info("K8S Deployment同步完成,集群: {}, Namespace: {}, 总数: {}, 保存: {}, Deployment未变化: {}, 仅更新Pod统计: {}",
|
||||
// 优化日志输出:单个Namespace的同步日志使用DEBUG级别,减少日志噪音
|
||||
// 详细信息在集群级别的汇总日志中体现
|
||||
log.debug("K8S Deployment同步完成,集群: {}, Namespace: {}, 总数: {}, 保存: {}, Deployment未变化: {}, 仅更新Pod统计: {}",
|
||||
externalSystem.getName(), namespace.getNamespaceName(), syncCount,
|
||||
deploymentsToSave.size(), unchangedCount, podStatsOnlyUpdateCount);
|
||||
|
||||
return syncCount;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user