將容器映像部署至 Azure Kubernetes Service

已完成

在此單元中,您會將容器映像部署至 Azure Kubernetes Service (AKS)。 使用 AKS,您可以設定 Kubernetes 叢集透過 部署讓 Kubernetes 叢集以預期狀態執行,這是為 Pod 和 ReplicaSet 提供宣告式更新的程序。 此狀態宣告會在資訊清單 YAML 檔案中定義,而 Kubernetes 控制器會在指示時將目前狀態變更為宣告的狀態。 您可以建立此 deployment.yml 資訊清單檔案,並指示您的 AKS 實例以預期狀態執行,並將 Pod 設定為拉取並執行您在上一個單元中推送至 Azure Container Registry 的 flightbookingsystemsample 容器映像。 此資訊清單宣告性地定義部署與服務。 Kubernetes 使用部署控制器來管理應用程式的 pod;你也可以用 kubectl create deployment建立命令式部署。

備註

如果您的工作階段已因閒置逾時,或是在另一個時間點或從另一個 CLI 執行此步驟,您可能必須使用下列命令重新初始化環境變數並重新驗證:

還原設定時使用的資源變數值。 請將下方的 <your-subscription-ID> 替換為您用於此模組的訂用帳戶 ID。 如果登入時出現訂閱選擇器,請選擇同一個訂閱。 一次執行一個驗證指令。 在 az account show 之後,確認有效訂閱是否符合設定,再繼續。 如果指令失敗,請停止並解決錯誤。

export AZ_RESOURCE_GROUP=java-containerization-demo-rg
export AZ_CONTAINER_REGISTRY=<your-container-registry>
export AZ_KUBERNETES_CLUSTER=java-containerization-demo-aks
export AZ_LOCATION=<your-Azure-region>
export AZ_KUBERNETES_CLUSTER_DNS_PREFIX=<your-unique-DNS-prefix-to-access-your-AKS-cluster>
az login
az account set --subscription "<your-subscription-ID>"
az account show --output table
az acr login --name "$AZ_CONTAINER_REGISTRY"

部署容器映像

現在,您會將 flightbookingsystemsample 容器映像部署至 AKS 叢集。 在 containerize-and-deploy-Java-app-to-Azure/Project/Airlines中,使用已安裝的文字編輯器建立名為 deployment.yml 的檔案。 這條路徑是相對於你複製儲存庫的父目錄。 如果你已經在 Project/Airlines 裡,就留在那裡,不要再切換成完整路徑。 建立檔案,然後從這個目錄執行後面的 kubectl apply -f deployment.yml 指令。

以下內容加入 deployment.yml,然後儲存檔案。 把 <AZ_CONTAINER_REGISTRY> 佔位符替換為你之前設定的 AZ_CONTAINER_REGISTRY 環境變數值。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flightbookingsystemsample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flightbookingsystemsample
  template:
    metadata:
      labels:
        app: flightbookingsystemsample
    spec:
      nodeSelector:
        kubernetes.io/os: linux
        kubernetes.io/arch: amd64
      containers:
      - name: flightbookingsystemsample
        image: <AZ_CONTAINER_REGISTRY>.azurecr.io/flightbookingsystemsample:latest
        resources:
          requests:
            cpu: "1"
            memory: "1Gi"
          limits:
            cpu: "2"
            memory: "2Gi"
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: flightbookingsystemsample
spec:
  type: LoadBalancer
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: flightbookingsystemsample

備註

如果你以專案根目錄中的 deployment_solution.yml 檔案作為起點,請將其映像更新為與此處所示相同的登錄映像和 :latest 標籤。 另外,也在 Deployment 的 spec.template.spec 下加入相同的 Linux AMD64 containers,與 nodeSelector 並列。 不要使用未改動的替代方案:它的映像檔和節點選擇器必須與此模組的建置平台相符。

在上述 deployment.yml中,檔案包含部署和服務。 部署可用來管理一組 Pod,而服務則用來允許對 Pod 的網路存取。 Pod 會設定為從 Azure Container Registry 提取單一映像 <AZ_CONTAINER_REGISTRY>.azurecr.io/flightbookingsystemsample:latest。 此服務設定為允許連入 HTTP Pod 流量進入連接埠 8080,類似於您在本機使用 -p 連接埠參數執行容器映像的方式。

節點選擇器限制 pod 只能使用 Linux AMD64 節點,以對應先前建立的 linux/amd64 映像檔。 它屬於 Deployment,而非 Service。 選擇器限制排程;它不會讓不相容的映像檔在其他架構上執行。

在設定叢集存取前,請確保在設定階段中建立 AKS 叢集已成功完成。 檢查它的配置狀態和目前的 Kubernetes 版本:

az aks show \
    --resource-group "$AZ_RESOURCE_GROUP" \
    --name "$AZ_KUBERNETES_CLUSTER" \
    --query '{provisioningState:provisioningState,currentKubernetesVersion:currentKubernetesVersion}' \
    --output table

如果指令失敗、provisioningState 不是 Succeeded,或 currentKubernetesVersion 不是採用 major.minor.patch 格式的非空版本,請不要繼續。

以下工具指示適用於設定時建立的本地 Linux、macOS 或 WSL Bash 會話,而非原生 PowerShell 或命令提示字元。 如果你在那個工作階段已經有可用的 kubectl 和 kubelogin 安裝,請保留它們,不要重新安裝。 用 kubelogin --version 和 kubectl version --client 檢查它們,並確保 kubectl 符合叢集的 支援版本偏斜政策。

否則,請用傳回的<control-plane-version>取代currentKubernetesVersion。 安裝相符的 kubectl 版本和 kubelogin 到使用者可寫入的位置:

KUBECTL_VERSION="<control-plane-version>"
if [[ "$KUBECTL_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    mkdir -p "$HOME/.local/bin" &&
    az aks install-cli \
        --client-version "$KUBECTL_VERSION" \
        --install-location "$HOME/.local/bin/kubectl" \
        --kubelogin-install-location "$HOME/.local/bin/kubelogin" &&
    export PATH="$HOME/.local/bin:$PATH" &&
    kubectl version --client &&
    kubelogin --version
else
    printf 'Stop: set KUBECTL_VERSION to the returned major.minor.patch version.\n' >&2
    false
fi

兩個安裝路徑都包含可執行檔名稱。 PATH export 只適用於目前的 shell;可在新的工作階段中重複執行,或將它加入適當的 Bash 啟動設定。 在繼續之前,先解決任何安裝或版本檢查失敗的問題。

兩個工具都已可用並驗證後,設定 kubectl 連接你的 AKS 叢集:

az aks get-credentials \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_KUBERNETES_CLUSTER

下列輸出是典型的:

Merged AZ_KUBERNETES_CLUSTER as current context in ~/.kube/config

在套用清單前,請先檢查實際的節點作業系統與架構:

kubectl get nodes \
    -o custom-columns='NAME:.metadata.name,OS:.status.nodeInfo.operatingSystem,ARCH:.status.nodeInfo.architecture'

此模組 linux/amd64 的建置路徑需要 Linux AMD64 節點。 若沒有匹配節點,則停止並解決不匹配後再繼續。 使用支援的 AMD64 節點池,或針對另一個支援的 Linux 節點架構重建、執行並推送映像檔,並更新部署的架構選擇器以符合該架構。 Docker --platform 選項不會建立或更改 AKS 節點池。

從 containerize-and-deploy-Java-app-to-Azure/Project/Airlines,將 deployment.yml 套用至你的叢集:

kubectl apply -f deployment.yml

下列輸出是典型的:

deployment.apps/flightbookingsystemsample created
service/flightbookingsystemsample created

使用下列命令監視部署的狀態:

kubectl get all

下列輸出是典型的:

kubectl get all
NAME                                            READY   STATUS    RESTARTS   AGE
pod/flightbookingsystemsample-b7fd6684f-4j8vf   1/1     Running   0          37s

NAME                                TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
service/flightbookingsystemsample   LoadBalancer   10.0.62.153   <external-IP>   8080:30534/TCP   37s
service/kubernetes                  ClusterIP      10.0.0.1      <none>          443/TCP          11h

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/flightbookingsystemsample   1/1     1            1           37s

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/flightbookingsystemsample-b7fd6684f   1         1         1       37s

Pod 的 Running 狀態並不能確認 Tomcat 是否完成部署該應用程式,或 HTTP 請求是否成功。 等待部署推出完成後,然後追蹤應用程式啟動日誌:

kubectl rollout status deployment/flightbookingsystemsample --timeout=300s &&
kubectl logs deployment/flightbookingsystemsample --tail=100 --follow

成功的部署會檢查 Kubernetes 的可用性。 由於此資訊清單沒有應用程式準備度探測,漸進部署並非 HTTP 健康測試。 請依照日誌追蹤,直到 Tomcat 報告伺服器啟動完成, AirlinesReservationSample.war 的部署也無錯誤地完成。 然後按 Ctrl+C 以停止追蹤日誌。 這只會停止日誌串流,不會停止容器。 如果部署作業或應用程式啟動失敗或未完成,請檢查日誌和 Pod 事件,而不是繼續做瀏覽器檢查。

以下歷史輸出展示了早期 Tomcat 10.1.33 影像中的啟動訊息。 這不是本模組更新映像的輸出;請使用您自己的日誌來驗證啟動,而不是期待相同的版本、時間戳或環境細節:

kubectl logs pod/flightbookingsystemsample-b7fd6684f-4j8vf
15-Nov-2024 12:31:51.208 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/10.1.33
15-Nov-2024 12:31:51.211 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Nov 7 2024 22:28:55 UTC
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.33.0
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            5.15.0-1074-azure
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/lib/jvm/msopenjdk-17
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           17.0.13+11-LTS
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Microsoft
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
15-Nov-2024 12:31:51.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
15-Nov-2024 12:31:51.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
15-Nov-2024 12:31:51.231 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]
15-Nov-2024 12:31:51.565 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
15-Nov-2024 12:31:51.602 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [616] milliseconds
15-Nov-2024 12:31:51.658 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
15-Nov-2024 12:31:51.659 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.33]
15-Nov-2024 12:31:51.689 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/AirlinesReservationSample.war]
15-Nov-2024 12:31:53.264 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
15-Nov-2024 12:31:55.155 INFO [main] com.sun.xml.ws.server.MonitorBase.createRoot Metro monitoring rootname successfully set to: com.sun.metro:pp=/,type=WSEndpoint,name=/AirlinesReservationSample-PriceAndSeats-PriceAndSeatsPort
15-Nov-2024 12:31:55.347 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletDelegate.<init> WSSERVLET14: XML-WS servlet initializing
WARNING:Error in the metadata of the table SEATS: table's row count in the metadata is 5 but 6 records have been found and loaded by UCanAccess. All will work fine, but it's better to repair your database.
15-Nov-2024 12:31:56.248 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletContextListener.contextInitialized WSSERVLET12: XML-WS context listener initializing
15-Nov-2024 12:31:56.249 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletContextListener.contextInitialized WSSERVLET12: XML-WS context listener initializing
15-Nov-2024 12:31:56.284 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/AirlinesReservationSample.war] has finished in [4,595] ms
15-Nov-2024 12:31:56.285 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]
15-Nov-2024 12:31:56.315 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [30] ms
15-Nov-2024 12:31:56.316 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples]
15-Nov-2024 12:31:56.439 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/examples] has finished in [123] ms
15-Nov-2024 12:31:56.440 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager]
15-Nov-2024 12:31:56.456 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [16] ms
15-Nov-2024 12:31:56.457 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/ROOT]
15-Nov-2024 12:31:56.468 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/ROOT] has finished in [11] ms
15-Nov-2024 12:31:56.468 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/host-manager]
15-Nov-2024 12:31:56.481 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/host-manager] has finished in [13] ms
15-Nov-2024 12:31:56.484 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
15-Nov-2024 12:31:56.501 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [4897] milliseconds

請留意服務的外部地址:

kubectl get service flightbookingsystemsample --watch

當 Azure 佈建負載平衡器時,EXTERNAL-IP 值一開始可能是 <pending>。 這可能需要幾分鐘,且本身並不代表部署失敗。 當地址出現時,按 Ctrl+C 停止監看。 如果配置未完成,請停止監看,並使用 kubectl describe service flightbookingsystemsample 檢查服務事件。

以下說明性輸出顯示該指派的位址出現的位置:

NAME                        TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
flightbookingsystemsample   LoadBalancer   10.0.62.153   <external-IP>   8080:30534/TCP   3m28s

備註

將下列 URL 中的 IP 位址 <external-IP> 取代為您先前執行該指令所得的 EXTERNAL-IP 值:

開啟瀏覽器,並前往 http://<external-IP>:8080/AirlinesReservationSample/ 的航班預約系統範例登陸頁面。 確認申請頁面有回應; Running 僅靠一個 Pod 或分配的 IP 並不代表應用程式已準備好。 您的瀏覽器看起來應該類似下列螢幕快照:

在瀏覽器中運行於 Azure Kubernetes Service 上的航班預訂系統登陸頁面截圖。

您可以選擇性地使用來自 tomcat-users.xml 的任何使用者登入,例如 someuser@azure.com: password。

疑難排解映像檔與平台不相符問題

對於 Pod 啟動失敗,請檢查 kubectl describe pods -l app=flightbookingsystemsample、kubectl logs deployment/flightbookingsystemsample --tail=100 和 kubectl get events --sort-by=.metadata.creationTimestamp。 一個 CrashLoopBackOff 狀態可能有多種原因,包括應用程式錯誤;不要假設每一次失敗都是架構不匹配。

如果你確認已部署的映像檔使用錯誤的平台,先以相符的平台設定重複建置、本地執行、映像檢查、登錄檔標記和推送步驟。 在修正後的映像檔成功重建、重新標記並置入同一 :latest 標籤後,明確替換正在運行的 pods:

kubectl rollout restart deployment/flightbookingsystemsample &&
kubectl rollout status deployment/flightbookingsystemsample --timeout=300s

對於此清單,:latest 預設為 imagePullPolicy: Always,因此替換 Pod 會解析目前的登錄檔標籤。 單純重新套用未更改的資訊清單不會觸發部署。 如果你自訂了拉取原則,請使用更新的映像標籤或摘要,然後改為更新 Deployment。 部署後再次進行啟動日誌和應用程式網址檢查。

清理資源

您在本課程模組中建立的資源可能會產生持續成本。 若要清除資源,請使用下列命令刪除包含這些資源的資源群組:

az group delete --name $AZ_RESOURCE_GROUP