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

相关推荐
桂月二二4 小时前
Java与容器化:如何使用Docker和Kubernetes优化Java应用的部署
java·docker·kubernetes
颜淡慕潇12 小时前
【K8S问题系列 | 20 】K8S如何删除异常对象(Pod、Namespace、PV、PVC)
后端·云原生·容器·kubernetes
didiplus14 小时前
Kubernetes 镜像拉取策略全解析:如何根据需求选择最佳配置?
云原生·容器·kubernetes
上海运维Q先生16 小时前
面试题整理17----K8s中request和limit资源限制是如何实现的
服务器·云原生·kubernetes
CloudPilotAI18 小时前
15条 Karpenter 最佳实践,轻松掌握弹性伸缩
kubernetes·弹性伸缩·karpenter
会飞的土拨鼠呀18 小时前
Flannel是什么,如何安装Flannel
运维·云原生·kubernetes
ether-lin19 小时前
DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(1)
ci/cd·kubernetes·devops
勇-子20 小时前
K8s 常用资源介绍
云原生·容器·kubernetes
大G哥20 小时前
k8s创建单例redis设置密码
数据库·redis·云原生·容器·kubernetes
勇-子1 天前
K8s DaemonSet的介绍
云原生·容器·kubernetes