本文介紹在ACK集群中部署工作負載的過程中可能遇到的常見問題及對應解決方案。
在ACK集群中使用容器運行應用的大致流程是什么?
您的應用代碼可部署在線下或者云上。不論何種語言的代碼,您都可以將其以容器化的方式部署、交付及運行。從開發代碼到運行容器化應用,大致需要以下四個階段。
編寫業務代碼。
使用Dockerfile構建鏡像。
Dockerfile:一個文本文件,包含了將代碼打包成鏡像所需的指令。具體操作,請參見在Dockerfile中使用構建打包鏡像并運行。
鏡像:軟件交付的載體。相較于傳統的如JAR、WAR、RPM包等,除了代碼外,鏡像還包含應用所依賴的軟件環境(容器運行時所需要的所有的文件集合)。使用鏡像可以快速生成一個容器,即運行的應用。
容器是一組具有隔離特性的進程集合,其特點是視圖隔離、資源可限制、具備獨立文件系統。您可以通過ACK對您所有的容器化應用進行全生命周期的高效管理。例如將某些Pod調度到指定的節點上,或者在業務負載升高時進行擴容操作。
上傳鏡像至鏡像倉庫。您可以使用容器鏡像服務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信息呈現給容器時可通過兩種方式: