本文介绍在ACK集群中部署工作负载的过程中可能遇到的常见问题及对应解决方案。
在ACK集群中使用容器运行应用的大致流程是什么?
您的应用代码可部署在线下或者云上。不论何种语言的代码,您都可以将其以容器化的方式部署、交付及运行。从开发代码到运行容器化应用,大致需要以下四个阶段。
编写业务代码。
使用Dockerfile构建镜像。
上传镜像至镜像仓库。您可以使用容器镜像服务ACR来存放镜像,并进行版本管理、分发拉取等操作。
ACR提供个人版和企业版,分别面向个人开发者和企业客户。更多信息,请参见什么是容器镜像服务ACR。
在ACK集群中部署工作负载,运行容器化应用,使用ACK提供的多种容器化应用管理能力,请参见工作负载。
为什么拉取镜像速度慢或拉取失败?
您可以按照以下方式对拉取镜像慢或失败的问题进行排查:
如果您拉取的是Docker Hub中的国外镜像,或当前网络条件比较差,建议您手动拉取镜像到本地节点,然后重启Pod,或将镜像上传到ACR中,使用ACR拉取镜像。具体操作,请参见使用企业版实例推送和拉取镜像和使用免密组件拉取容器镜像。
如果您使用ACR拉取镜像,请确认用户名或密码是否正确。建议使用免密插件拉取镜像,具体操作,请参见使用免密组件拉取容器镜像。
确认发起请求的客户端是否具备公网能力,如果没有,您需要为客户端设置公网。
如何进行ACK应用故障排查?
ACK应用故障主要是由Pod、Deployment(StatefulSet/DaemonSet)控制器和Service的问题导致,您需要检查以下几类问题。
检查Pod
关于Pod异常问题的处理,请参见Pod异常问题排查。
检查Deployment
创建Deployment、DaemonSet、StatefulSet或Job等资源时,可能为Pod的问题。请参见Pod异常问题排查检查Pod的问题。
您也可以通过查看和Deployment相关的事件及日志来定位问题:
本文以Deployment为例进行介绍,在DaemonSet、StatefulSet或Job等资源中查看事件和日志的操作类似。
登录容器服务管理控制台,在左侧导航栏选择集群。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
在无状态页面,单击目标Deployment名称。然后单击事件或日志,即可通过异常信息定位问题。
关于创建StatefulSet遇到的更多问题。请参见Forced Rollback。
检查Service
服务(Service)可以为一组Pod提供负载均衡的功能。以下介绍如何定位与Service相关的几类常见问题:
检查Service的Endpoints。
登录Kubernetes集群的Master节点。详情请参见获取集群KubeConfig并通过kubectl工具连接集群。
执行以下命令,查看Service的Endpoints。
以下代码中
[$Service_Name]
为目标Service的名称。kubectl get endpoints [$Service_Name]
请确保ENDPOINTS值的地址个数和您期望与该Service匹配的Pod个数相同。例如,您使用Deployment部署了应用,其副本数为3,那么ENDPOINTS值的地址个数一定是3个。
Service中缺少Endpoints地址
如果您的Service中缺少Endpoints地址,可以通过Service的selector查询Service与Pod是否相关联,示例如下:
若您服务的YAML文件信息如下图所示时。
执行以下命令,核对返回的Pod是否为您已关联的Pod。
kubectl get pods --selector=app=[$App] -n [$Namespace]
说明[$App]
为关联的Pod名称。[$Namespace]
为服务所在的命名空间,如果服务在默认空间,则无需指定。
如果返回的Pod是您关联的Pod,但没有Endpoints地址,很可能是您没有为Service指定正确的端口。如果Service中指定的端口实际上在Pod中没有被监听,那么该Pod不会被添加到ENDPOINTS列表中,因此,请确保Service指定的容器端口在Pod中可以访问,命令如下。
curl [$IP]:[$Port]
说明[$IP]
为第1步YAML文件中的clusterIP。[$Port]
为第1步YAML文件中的port值。具体测试方法以实际环境为准。
网络转发问题
如果您的客户端可以连接Service,并且Endpoints中的地址正确,但连接很快断开,那么可能是流量不能转发到您的Pod上,通常需要进行以下检查:
Pod是否正常工作。
定位Pod问题。具体操作,请参见Pod异常问题排查。
Pod地址是否正常连通。
执行以下命令,获取Pod的IP地址。
kubectl get pods -o wide
登录任意节点,使用ping命令测试Pod的IP地址,确认网络连接正常。
应用程序是否正常监听端口。
如果您的应用程序监听80端口,那么您需要在Service中指定容器端口为80。在任意节点上执行
curl [$IP]:[$Port]
命令,查看Pod中容器的端口是否正常。
如何手动升级Helm的版本?
登录到Kubernetes集群。更多信息,请参见获取集群KubeConfig并通过kubectl工具连接集群。
执行以下命令安装Tiller。
其中镜像地址可使用对应地域的VPC域名,例如,杭州地域的机器替换为
registry-vpc.cn-hangzhou.aliyuncs.com/acs/tiller:v2.11.0
。helm init --tiller-image registry.cn-hangzhou.aliyuncs.com/acs/tiller:v2.11.0 --upgrade
等待tiller健康检查通过,执行
helm version
命令查看版本升级情况。说明这里只会升级Helm服务端版本,客户端可以通过直接下载对应的Client Binary使用。
请下载阿里云支持的最新客户端版本Helm client 2.11.0。
Helm客户端和服务端版本都升级完毕后,执行以下命令查看Helm版本。
helm version
预期输出:
Client: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b****", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b****", GitTreeState:"clean"}
如何支持私有镜像?
执行以下命令创建Secret。
kubectl create secret docker-registry regsecret --docker-server=registry-internal.cn-hangzhou.aliyuncs.com --docker-username=abc****@aliyun.com --docker-password=**** --docker-email=abc****@aliyun.com
regsecret
:指密钥的键名称,可自定义。--docker-server
:指Docker仓库地址。--docker-username
:指Docker仓库用户名。--docker-password
:指Docker仓库登录密码。可选:
--docker-email
:指邮件地址。
您可以通过以下两种方法进行操作:
手动配置私有镜像
在YAML文件中加入密钥参数。
containers: - name: foo image: registry-internal.cn-hangzhou.aliyuncs.com/abc/test:1.0 imagePullSecrets: - name: regsecret
说明imagePullSecrets
是声明拉取镜像时需要指定的密钥。regsecret
必须和上面生成密钥的键名一致。image
中的Docker仓库名称必须和--docker-server
中的Docker仓库名一致。
更多信息,请参见使用私有仓库。
自动配置私有镜像实现无密钥编排
说明为了避免每次使用私有镜像部署时都需要引用密钥,您可以将Secret添加到Namespace的Default Service Account中。更多信息,请参见Add ImagePullSecrets to a service account。
执行以下命令,查看创建的拉取私有镜像的Secret。
kubectl get secret regsecret
预期输出:
NAME TYPE DATA AGE regsecret kubernetes.io/dockerconfigjson 1 13m
本例中采用手动配置的方式,修改命名空间的默认服务账号Default,从而将此Secret作为imagePullSecret。
创建一个sa.yaml配置文件,将服务账号Default的配置导入到该文件中。
kubectl get serviceaccounts default -o yaml > ./sa.yaml
执行以下命令查看sa.yaml文件的详情。
cat sa.yaml
预期输出:
apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: 2015-08-07T22:02:39Z name: default namespace: default resourceVersion: "243024" #注意该项selfLink: /api/v1/namespaces/default/serviceaccounts/default。 uid: 052fb0f4-3d50-11e5-b066-42010af0**** secrets: - name: default-token-uudgeoken-uudge
执行
vim sa.yaml
命令,删除resourceVersion,并增加拉取镜像的密钥配置项imagePullSecrets。修改后的配置如下所示:apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: 2015-08-07T22:02:39Z name: default namespace: default selfLink: /api/v1/namespaces/default/serviceaccounts/default uid: 052fb0f4-3d50-11e5-b066-42010af0**** secrets: - name: default-token-uudge imagePullSecrets: #增加该项。 - name: regsecret
执行以下命令将sa.yaml配置文件替换Default的服务账号配置。
kubectl replace serviceaccount default -f ./sa.yaml
预期输出:
serviceaccount "default" replaced
创建Tomcat示例应用。
Tomcat编排示例tomcat.yaml文件如下所示:
apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deployment labels: app: tomcat spec: replicas: 1 selector: matchLabels: app: tomcat template: metadata: labels: app: tomcat spec: containers: - name: tomcat image: registry-internal.cn-hangzhou.aliyuncs.com/abc/test:1.0 #替换为您自己的私有镜像地址Ports。 - containerPort: 8080
执行以下命令创建Tomcat应用。
kubectl create -f tomcat.yaml
Pod启动成功后执行以下命令,可以看到预期的配置。
kubectl get pod tomcat-**** -o yaml
预期输出:
spec: imagePullSecrets: - nameregsecretey
如何在国外地域的ACK集群中使用中国内地地域的容器镜像服务企业版的镜像?
在此种场景下,您需要在中国内地地域购买标准版和高级版的容器镜像服务企业版,在国外地域购买基础版的容器镜像服务企业版。
完成购买后,您需要使用同步实例的方法将中国内地地域的镜像同步到国外地域,具体操作,请参见同账号同步实例。在国外地域的容器镜像服务企业版中获取镜像地址,然后在国外地域的ACK集群中使用镜像地址创建应用。
如果您使用容器镜像服务个人版,同步镜像的速度将非常慢。如果您使用的是自建仓库,您需要购买GA加速。
自建仓库和购买GA加速的成本比购买容器镜像服务企业版高,推荐您使用容器镜像服务企业版。
关于容器镜像服务企业版的计费方式,请参见计费说明。
更新应用时,如何实现K8s零中断滚动更新?
旧的应用删除,新的应用在创建过程中产生了短暂的5XX
访问错误。此问题是由于应用滚动更新时,Pod变更同步到CLB会存在秒级延迟,因此会出现5XX
错误。您可以通过配置优雅中断等方式解决此问题,以实现K8s零中断滚动更新。具体操作,请参见如何实现K8s零中断滚动更新?。
如何获取镜像?
您可以使用容器镜像服务ACR,来构建以及拉取镜像。具体信息,请参见管理镜像。
如何重启容器?
无法直接操作重启单个容器,您可以通过以下方式实现同样的效果:
执行以下命令查看容器状态,并确定待重启的容器。
kubectl get pods
删除Pod:直接删除Pod也会触发控制器(例如Deployment、DaemonSet等)重新创建新的Pod实例,从而达到重启容器的目的。删除单个Pod的命令如下:
kubectl delete pod <pod-name>
删除Pod后,Kubernetes会根据对应的控制器自动创建一个新的Pod进行替换。
说明在实际生产环境中,应避免手动直接操作Pod,而是通过控制ReplicaSet、Deployment等对象来进行容器的管理和更新,以确保集群状态的一致性和正确性。
执行以下命令验证容器状态,确认容器状态为Running重启成功。
kubectl get pods
如何修改Deployment的命名空间?
如果您期望将服务从一个命名空间转移到另一个命名空间,您需要将服务的归属命名空间进行相应的修改。当执行命名空间变更时,还需要手动修改服务的持久化卷声明、配置对象(ConfigMaps)、保密字典(Secrets)以及其他依赖资源的命名空间,确保服务正常运行。
通过
kubectl get
命令以YAML格式导出资源配置。kubectl get deploy <deployment-name> -n <old-namespace> -o yaml > deployment.yaml
编辑deployment.yaml,在
namespace
参数替换成新的命名空间后保存并退出。apiVersion: apps/v1 kind: Deployment metadata: annotations: generation: 1 labels: app: nginx name: nginx-deployment namespace: new-namespace # 替换为新的命名空间。 ... ...
使用
kubectl apply
命令将服务更新至新命名空间。kubectl apply -f deployment.yaml
使用
kubectl get
命令在新命名空间下查看服务。kubectl get deploy -n new-namespace
如何将Pod信息呈现给容器?
ACK与社区Kubernetes保持一致性,遵循社区规范。将Pod信息呈现给容器时可通过两种方式: