调用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等信息。

相关推荐
退役小学生呀5 小时前
十、K8s集群资源合理化分配
linux·云原生·容器·kubernetes·k8s
Johny_Zhao14 小时前
Docker + CentOS 部署 Zookeeper 集群 + Kubernetes Operator 自动化运维方案
linux·网络安全·docker·信息安全·zookeeper·kubernetes·云计算·系统运维
木鱼时刻2 天前
容器与 Kubernetes 基本概念与架构
容器·架构·kubernetes
指月小筑2 天前
开源 vGPU 方案 HAMi: core&memory 隔离测试
人工智能·云原生·容器·kubernetes·开源·gpu算力
chuanauc2 天前
Kubernets K8s 学习
java·学习·kubernetes
庸子3 天前
基于Jenkins和Kubernetes构建DevOps自动化运维管理平台
运维·kubernetes·jenkins
李白你好3 天前
高级运维!Kubernetes(K8S)常用命令的整理集合
运维·容器·kubernetes
Connie14513 天前
k8s多集群管理中的联邦和舰队如何理解?
云原生·容器·kubernetes
伤不起bb3 天前
Kubernetes 服务发布基础
云原生·容器·kubernetes
别骂我h3 天前
Kubernetes服务发布基础
云原生·容器·kubernetes