调用k8s api接口实现服务镜像的更新与回滚

最近接到一个需求,自动更新替换k8s集群中某些服务的镜像,并支持回滚到原先版本。

我首先想到的是使用 kubectl命令,通过编写一个shell脚本,并传送到k8s集群某个管理节点,执行类似下面这种命令:

arduino 复制代码
kubectl set image deployment/<deployment-name> <container-name>=<new-image>

其中,是服务的Deployment名称,是服务容器的名称,是新的镜像名称。

例如,如果服务的Deployment名称为my-service,容器名称为my-container,新的镜像名称为my-registry/my-image:latest,则命令如下:

kubectl set image deployment/my-service my-container=my-registry/my-image:latest

但是后续了解到在部署该k8s集群时,不会预装 kubectl 命令,所以上述方法有局限性,需要客户先手动安装 kubectl 命令。

后来选择调用 k8s 的api接口进行实现镜像版本替换。

bash 复制代码
/apis/apps/v1/namespaces/{namespace}/deployments/{name}

相关接口的解释在k8s官网中有解释,但是感觉过于简单,具体的调用方法实现还是借助的chatgpt

官网文档地址: kubernetes.io/docs/refere...

示例代码如下:

python 复制代码
import requests
​
def update_service_image(deployment_name, container_name, new_image):
    api_server = "<api-server>"
    token = "<your-token>"
    namespace = "<namespace>"
    
    # 构建API URL
    url = f"{api_server}/apis/apps/v1/namespaces/{namespace}/deployments/{deployment_name}"
    
    # 构建请求头,包括认证信息
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/strategic-merge-patch+json"
    }
    
    # 构建要更新的镜像的部分
    patch = {
        "spec": {
            "template": {
                "spec": {
                    "containers": [
                        {
                            "name": container_name,
                            "image": new_image
                        }
                    ]
                }
            }
        }
    }
    
    # 发送 PATCH 请求
    response = requests.patch(url, headers=headers, json=patch, verify=False)
    
    if response.status_code == 200:
        print("Service image updated successfully")
    else:
        print("Failed to update service image. Status code:", response.status_code)
​
# 使用示例
update_service_image("my-deployment", "my-container", "new-image:latest")

但是该api接口返回200只会保证修改deployement相关配置成功,并不意味着后续的滚动升级也会成功。

常见的一个错误场景就是替换成一个不存在的镜像版本,调用该接口时也会成功,返回200。

但是在后续的滚动升级时,新的pod会出现异常,提示镜像不存在,更新失败。

所以我们要调用 GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}/status接口来获取deployment相关状态来判断是否更新成功。

有一个情况注意下,调用完更新接口后立即调用该查询接口时会返回旧版本状态,不包含新版本的状态,建议先停顿一会再调用该接口。

如何根据上述接口返回的参数进行判断是否成功呢?

上述接口返回信息里有这几个信息:

json 复制代码
 "status": { "observedGeneration": 3, "replicas": 3, "readyReplicas": 3, "availableReplicas": 3}

参考kubernets源码中的方法判断:

位置:pkg/controller/deployment/util/deployment_util.go:708

代码:

ini 复制代码
func DeploymentComplete(deployment *apps.Deployment, newStatus *apps.DeploymentStatus) bool {
  return newStatus.UpdatedReplicas == *(deployment.Spec.Replicas) &&
    newStatus.Replicas == *(deployment.Spec.Replicas) &&
    newStatus.AvailableReplicas == *(deployment.Spec.Replicas) &&
    newStatus.ObservedGeneration >= deployment.Generation
}

如何进行回滚呢?

在kunernetes官网中并没有搜到相关api介绍,咨询chatgpt给出的方法如下,但是没有生效,没有找到失效的原因:

python 复制代码
import requests
import json
​
def rollback_deployment(deployment_name, namespace):
    # 构建API请求的URL
    url = f"https://your-kubernetes-api-url/apis/apps/v1/namespaces/{namespace}/deployments/{deployment_name}"
​
    # 获取Deployment的当前修订版本
    current_revision = get_current_revision(deployment_name, namespace)
​
    # 构建回滚请求的Body
    body = {
        "kind": "Deployment",
        "apiVersion": "apps/v1",
        "metadata": {
            "name": deployment_name,
            "annotations": {
                "deployment.kubernetes.io/revision": str(current_revision)  # 回滚到当前修订版本
            }
        }
    }
​
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_API_TOKEN"  # 替换为你的API Token
    }
​
    # 发送回滚请求
    response = requests.patch(url, headers=headers, data=json.dumps(body), verify=False)
​
    if response.status_code == 200:
        print("Deployment回滚成功!")
    else:
        print(f"Deployment回滚失败:{response.text}")
​
def get_current_revision(deployment_name, namespace):
    # 构建API请求的URL
    url = f"https://your-kubernetes-api-url/apis/apps/v1/namespaces/{namespace}/deployments/{deployment_name}"
​
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_API_TOKEN"  # 替换为你的API Token
    }
​
    # 发送请求获取Deployment的���细信息
    response = requests.get(url, headers=headers, verify=False)
​
    if response.status_code == 200:
        deployment_info = json.loads(response.text)
        current_revision = deployment_info["metadata"]["annotations"]["deployment.kubernetes.io/revision"]
        return current_revision
    else:
        print(f"获取Deployment信息失败:{response.text}")
        return None
​
# 使用示例
rollback_deployment("my-deployment", "my-namespace")

后面最终实行的方法是在更新前先保留一份deployment配置备份,然后在回滚时直接替换成这个配置即可。

但是直接替换会提示错误,需要删除之前配置metadata.creationTimestampmetadata.generationmetadata.resourceVersion等信息。

相关推荐
Connie14515 小时前
记一次K8s故障告警排查(Grafna告警排查)
云原生·容器·kubernetes·grafana
谷隐凡二13 小时前
Kubernetes主从架构简单解析:基于Python的模拟实现
python·架构·kubernetes
陈陈CHENCHEN13 小时前
SuperMap iManager for K8s 离线环境镜像仓库 Containerd 部署
kubernetes
会飞的小蛮猪15 小时前
Ubuntu24.04 基于Containerd部署K8s1.34(私服部署)
docker·云原生·kubernetes
间彧1 天前
Kubernetes滚动发布详解
kubernetes
间彧1 天前
在实际生产环境中,Kubernetes声明式API如何实现蓝绿部署、金丝雀发布等高级部署策略?
kubernetes
间彧1 天前
Kubernetes声明式API相比传统命令式API在故障恢复场景下的具体优势有哪些?
kubernetes·github
间彧1 天前
为什么说Kubernetes的API设计是其成功的关键因素之一?
kubernetes
间彧1 天前
Kubernetes Deployment 配置简化实战:从复杂到高效
kubernetes
可爱的小小小狼1 天前
k8s:服务网格Service Mesh(服务网格)istio和envoy
kubernetes·istio·service_mesh