學習路徑:將單體式應用程式轉換為 GKE 應用程式 - 將模組化應用程式容器化


這是學習路徑的第四個教學課程,說明如何將單體式應用程式模組化及容器化。

這個學習路徑包含下列教學課程:

  1. 總覽
  2. 瞭解單體式架構
  3. 將單體應用程式模組化
  4. 準備將模組化應用程式容器化
  5. 將模組化應用程式容器化 (本教學課程)
  6. 將應用程式部署至 GKE 叢集

在上一個教學課程「準備將模組化應用程式容器化」中,您瞭解了為準備容器化,Cymbal Books 應用程式的模組化版本需要進行哪些變更。在本教學課程中,您會將應用程式容器化。

費用

完成本教學課程不會產生任何費用。不過,按照本系列下一個教學課程的步驟操作時,系統會向您的Google Cloud 帳戶收費。啟用 GKE 並將 Cymbal Books 應用程式部署至 GKE 叢集後,就會開始產生費用。這些費用包括 GKE 的叢集費用 (如定價頁面所述),以及執行 Compute Engine VM 的費用。

為避免產生不必要的費用,請務必在完成本教學課程後停用 GKE 或刪除專案。

事前準備

開始本教學課程前,請先完成本系列先前的教學課程。如要查看整個系列課程的總覽,以及特定教學課程的連結,請參閱「學習路徑:將單體式應用程式轉換為 GKE 應用程式 - 總覽」。

設定環境

在本節中,您將設定環境,以便將模組化應用程式容器化。具體來說,您會執行下列步驟:

  1. 選取或建立 Google Cloud 專案
  2. 啟用必要的 API
  3. 將 Cloud Shell 連線至 Google Cloud 專案
  4. 設定預設環境變數
  5. 在 Artifact Registry 中建立存放區
  6. 為 Artifact Registry 設定 Docker
  7. 取得教學課程程式碼

選取或建立 Google Cloud 專案

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

啟用必要的 API

如要在 Google Cloud 專案中使用容器映像檔和 Kubernetes,請啟用下列 API:

  • Artifact Registry API:這項 API 可啟用 Artifact Registry,這項服務可用於儲存及管理容器映像檔。
  • Kubernetes Engine API:這個 API 可存取 GKE。

如要啟用這些 API,請前往啟用 API Google Cloud 控制台。

將 Cloud Shell 連線至 Google Cloud 專案

Google Cloud 專案設定完成後,請啟動 Cloud Shell 執行個體,並連結至 Google Cloud專案。Cloud Shell 是一種指令列工具,可讓您直接在瀏覽器中建立及管理專案資源。Cloud Shell 已預先安裝兩項重要工具:gcloud CLIkubectl CLI。在本教學課程中,您將使用 gcloud CLI 與 Google Cloud 互動,而在下一個教學課程中,您將使用 kubectl CLI 管理在 GKE 上執行的 Cymbal Books 應用程式。

如要將 Cloud Shell 執行個體連結至專案,請按照下列步驟操作: Google Cloud

  1. 前往 Google Cloud 控制台:

    Google Cloud console

  2. 在控制台中,按一下「啟用 Cloud Shell」按鈕:啟用 Cloud Shell

    此時 Cloud Shell 工作階段會在控制台底部的頁框中開啟,

  3. 使用下列指令,在 Google Cloud CLI 中設定預設專案:

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替換為您在上一節建立或選取的專案 ID,選取或建立 Google Cloud 專案。 專案 ID 是專屬字串,可將您的專案與 Google Cloud中的所有其他專案區分開來。如要找出專案 ID,請前往專案選取器。您可以在該頁面查看每個專案的專案 ID。 Google Cloud

設定預設環境變數

為簡化本教學課程中執行的指令,您現在要在 Cloud Shell 中設定一些環境變數。這些變數會儲存專案 ID、存放區區域和映像檔標記等值。定義這些變數後,您就可以在多個指令中重複使用這些變數,方法是參照變數名稱 (例如 $REPOSITORY_NAME),而不必每次都重新輸入或取代值。這種做法可讓您更輕鬆地跟上本教學課程,並降低出錯風險。

如要使用 Cloud Shell 設定環境,請執行下列步驟:

export PROJECT_ID=$(gcloud config get project)
export REPOSITORY_REGION=REPOSITORY_REGION
export REPOSITORY_NAME=REPOSITORY_NAME
export REPOSITORY_DESCRIPTION="REPOSITORY_DESCRIPTION"
export TAG=TAG

更改下列內容:

  • REPOSITORY_REGION:您要代管 Artifact Registry 存放區的區域。例如 us-central1 (愛荷華州)、us-west1 (奧勒岡州) 或 europe-west1 (比利時)。如需完整地區清單,請參閱「地區和區域」。
  • REPOSITORY_NAME:存放區名稱。 例如:book-review-service-repo
  • REPOSITORY_DESCRIPTION:存放區用途的簡短說明。例如:"Repository for storing Docker images for the book review service"
  • TAG:要套用至圖片的標記。標記是可附加至特定容器映像檔版本的標籤。您可以採用下列標記命名慣例,清楚指出不同版本的映像檔:
    • v1
    • v1.2.3
    • 描述性標記,例如 feature-x-dev
    • 指出環境的標記,例如 test

在 Artifact Registry 中建立存放區

接著,在 Artifact Registry 中建立存放區。存放區是儲存容器映像檔的儲存位置。建構容器映像檔時,您需要將其儲存在某處,以便稍後部署至 Kubernetes 叢集。您可以在 Google Cloud 專案中建立及管理這些存放區。

如要在 Artifact Registry 中建立存放區,請執行下列指令:

gcloud artifacts repositories create ${REPOSITORY_NAME} \
    --repository-format=docker \
    --location=${REPOSITORY_REGION} \
    --description="${REPOSITORY_DESCRIPTION}"

指令成功輸出內容如下所示:

Waiting for operation [...] to complete...done.
Created repository [book-review-service-repo].

為 Artifact Registry 設定 Docker

接著,您要設定 Docker,確保 Docker 能安全地與Google Cloud的 Artifact Registry 通訊。Docker 是一種工具,可用於在不同環境中以一致的方式封裝及執行軟體。下一節將進一步說明 Docker 的運作方式。目前您需要設定,讓其連線至 Artifact Registry。

如果未以這種方式設定 Docker,您就無法將容器映像檔推送至 Artifact Registry (這是本教學課程稍後會執行的工作)。您也無法從 Artifact Registry 提取容器映像檔,並將其部署至 GKE 叢集 (您會在下一個教學課程中執行這項工作)。

如要將 Docker 設為向 Artifact Registry 進行驗證,請執行下列指令:

gcloud auth configure-docker ${REPOSITORY_REGION}-docker.pkg.dev

取得教學課程程式碼

Cloud Shell 環境設定完成後,您需要在 Cloud Shell 中下載教學課程程式碼。即使您先前已在本機電腦上複製存放區,仍需在 Cloud Shell 執行個體上再次複製。

雖然您可以在本機完成本教學課程,但必須手動安裝及設定 Docker、kubectl 和 gcloud CLI 等多種工具。Cloud Shell 預先設定了所有這些工具,因此使用起來更輕鬆。

在 Cloud Shell 執行個體中,執行下列指令來複製 GitHub 存放區:

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git

容器化基礎知識:容器映像檔、容器和 Dockerfile

您已設定環境並下載容器化程式碼,現在可以開始將應用程式容器化。將應用程式容器化時,請使用 Dockerfile 將 Cymbal Books 的每個模組 (首頁、書籍詳細資料、圖片和書評) 封裝到容器映像檔中。應用程式部署至 GKE 叢集後,Kubernetes 會使用這些容器映像檔,在叢集中建立執行中的容器。

以下各節將詳細說明這些概念。

什麼是容器化?

容器化會將模組和所有依附元件 (例如程式庫和設定檔) 打包成一個單元,稱為容器映像檔。開發人員可使用這個容器映像檔,在任何環境 (從開發人員的筆電到測試伺服器或 Kubernetes 生產環境叢集) 中建立及執行容器。

什麼是容器映像檔?

容器映像檔包含執行應用程式所需的所有檔案。這些檔案包括應用程式程式碼本身、系統程式庫、執行階段環境 (例如 Python 解譯器)、靜態資料和任何其他依附元件。

在本教學課程中,您會為書評應用程式的每個模組建立容器映像檔。

什麼是容器?

容器是獨立的環境,可執行容器映像檔中的程式碼。您可以透過兩種方式建立容器:在開發期間使用 docker run 指令進行測試,或是將容器映像檔部署至 Kubernetes 叢集。

在容器化版本的 Cymbal Books 應用程式中,模組化應用程式的每個模組都會在自己的容器中執行:

  • 首頁容器會執行首頁模組,並處理對 / 的要求。
  • 書籍詳細資料容器會執行書籍詳細資料模組,並為 /book/1/book/3 等端點提供資料。
  • 書評容器會執行書評模組,並管理對 /book/2/reviews 等端點的要求。
  • 圖片容器會執行圖片模組,並為 /images/fungi_frontier.jpg 等端點提供書籍封面圖片。

容器的主要優勢在於,Kubernetes 可在需要時自動建立更多容器。舉例來說,如果許多使用者都在閱讀書評,Kubernetes 可以啟動額外的書評容器來處理負載。

如要在未使用容器的模組化應用程式中實作擴縮功能,您需要編寫自訂程式碼,啟動模組的新例項,並在這些例項之間分配流量。Kubernetes 內建這項資源調度功能,您不必編寫任何自訂資源調度程式碼。

什麼是 Dockerfile?

Dockerfile 是指令碼,用於定義如何將模組封裝至容器映像檔。在本教學課程中,您不需要建立任何 Dockerfile,因為稍早複製的 GitHub 存放區中已提供這些檔案。在 kubernetes-engine-samples/quickstarts/monolith-to-microservices/containerized/ 的本機副本中,每個模組的目錄都包含自己的 Dockerfile。

舉例來說,您可以在 Cloud Shell 執行個體的 kubernetes-engine-samples/quickstarts/monolith-to-microservices/containerized/home_app/Dockerfile 中找到 home_app 模組的 Dockerfile。這個 Dockerfile 如下所示:

# Dockerfile for home_app
FROM python:3.9-slim #line 1
WORKDIR /app #line 2
COPY requirements.txt . #line 3
RUN pip install --no-cache-dir -r requirements.txt #line 4
COPY home_app.py . #line 5
COPY templates/ ./templates/ #line 6
COPY static/ ./static/ #line 7
CMD ["python", "home_app.py"] #line 8

這個 Dockerfile 會執行下列步驟,為 home_app 模組建立容器映像檔:

  • 第 1 行: FROM python:3.9-slim 將 Python 3.9 解譯器及其必要檔案下載到容器映像檔。這些檔案可讓模組執行。
  • 第 2 行: WORKDIR /app 會在容器內建立名為 /app 的目錄,並將這個目錄設為目前的工作目錄。在容器內執行的所有指令都會從這個目錄執行。
  • 第 3 和 4 行: 會將本機電腦中的 requirements.txt 檔案複製到容器映像檔的 /app 目錄。COPY requirements.txt .requirements.txt 檔案會列出 home_app.py 需要的所有 Python 程式庫。RUN pip install 這行程式碼會將這些程式庫安裝到容器映像檔中。
  • 第 5 至 7 行:這些行中顯示的 COPY 指令,會將模組的程式碼 (home_app.py) 和支援檔案 (範本和靜態資產) 複製到容器映像檔中的 /app 目錄。
  • 第 8 行:CMD 指定 Docker 在容器啟動時執行的預設指令。在這個 Dockerfile 中,CMD ["python", "home_app.py"]會指示 Docker 在容器啟動時,使用 Python 解譯器自動執行 home_app.py 模組。

容器化如何強制執行更嚴格的資料隔離

Dockerfile 的第 5 到 7 行 (如上一節所述) 說明,相較於應用程式的模組化版本,容器化如何強制執行更嚴格的資料隔離。在先前的教學課程中,您在「只允許每個模組存取所需資料」一節中瞭解到,應用程式的模組化版本會將資料整理到不同的目錄中,但模組仍共用相同檔案系統,且可能存取彼此的資料。

在應用程式的容器化版本中,每個模組的容器只包含必要檔案。舉例來說,如果 home_app 模組不需要存取書籍評論資料,該資料就不會存在於 home_app 容器中。根據預設,容器無法存取其他容器的檔案,除非明確設定允許存取。這有助於確保每個模組完全隔離,並防止意外或未經授權的資料存取。

在下一節中,您會看到 docker build 指令如何將 Dockerfile 做為輸入內容,並按照 Dockerfile 中的指示建立容器映像檔。

使用 Docker 建構容器映像檔

在本節中,您將為每個書評模組建構 Docker 容器映像檔,並將其推送至 Artifact Registry 存放區。您會在後續教學課程中使用這些容器映像檔,在 Kubernetes 中部署及執行 Cymbal Books 範例應用程式。

  1. 前往容器化應用程式的根目錄:

    cd kubernetes-engine-samples/quickstarts/monolith-to-microservices/containerized/
    
  2. 使用 docker build 指令建立容器映像檔:

    docker build -t ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/home-app:${TAG} ./home_app
    docker build -t ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-details-app:${TAG} ./book_details_app
    docker build -t ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-reviews-app:${TAG} ./book_reviews_app
    docker build -t ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/images-app:${TAG} ./images_app
    
  3. 查看在 Cloud Shell 執行個體中建構的容器映像檔:

    docker images
    

    確認清單中顯示下列圖片:

    • home-app
    • book-details-app
    • book-reviews-app
    • images-app

    如果列出所有四張圖片,表示您已成功建立容器映像檔。

在 Cloud Shell 中測試容器

如要確認容器映像檔是否建構正確,可以將其做為容器執行,並在 Cloud Shell 中測試端點。

book_details_appbook_reviews_appimages_app 容器不需要彼此通訊,因此可以個別測試。不過,使用 Docker 測試 home_app 容器很困難,因為 home_app 會設定為尋找使用服務名稱 (例如 http://book-details-service:8081) 的其他容器。

雖然可以透過找出每個容器的 IP 位址,並將 home_app 設為使用這些位址 (而非服務名稱) 來測試 home_app 容器,但這種做法需要投入大量心力。建議您先將應用程式部署至 Kubernetes 叢集,再測試 home_app 容器。應用程式位於叢集上後,您可以判斷主模組是否正常運作。

請按照下列步驟測試容器:

  1. 啟動 book_details_appbook_reviews_appimages_app 容器:

    docker run -d -p 8081:8080 ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-details-app:${TAG}
    docker run -d -p 8082:8080 ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-reviews-app:${TAG}
    docker run -d -p 8083:8080 ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/images-app:${TAG}
    
  2. 列出所有使用中的容器,確認容器是否正在執行:

    docker ps
    

    這項指令的輸出內容應顯示三個正在執行的容器,狀態為 Up

    CONTAINER ID   IMAGE                PORTS                        STATUS
    a1b2c3d4e5f6   REGION/.../details   0.0.0.0:8081->8080/tcp       Up
    g7h8i9j0k1l2   REGION/.../reviews   0.0.0.0:8082->8080/tcp       Up
    m3n4o5p6q7r8   REGION/.../images    0.0.0.0:8083->8080/tcp       Up
    
  3. 如要測試 book_details_app 容器的端點,請使用下列 curl 指令:

    curl http://localhost:8081/books
    curl http://localhost:8081/book/1
    curl http://localhost:8081/book/2
    curl http://localhost:8081/book/3
    

    這些指令都會以 JSON 格式傳回資料。舉例來說,curl http://localhost:8081/book/1 指令的輸出內容如下所示:

    {"author":"Aria Clockwork","description":"In a world where time is a tangible substance, a young clockmaker discovers she can manipulate the fabric of time itself, leading to unforeseen consequences in her steampunk-inspired city.","id":1,"image_url":"zephyrs_timepiece.jpg","title":"Zephyr's Timepiece","year":2023}
    
  4. 使用這個 curl 指令,從 book_reviews_app 容器擷取書籍評論:

    curl http://localhost:8082/book/1/reviews
    

    這項指令會以 JSON 格式傳回書籍 1 的 20 則評論清單。以下是清單中的其中一則評論範例:

    {
    "content": "The concept of time as a tangible substance is brilliantly explored in 'Zephyr's Timepiece'.",
    "rating": 5
    }
    
  5. 測試 images_app 容器:

    1. 按一下 **Web Preview** 按鈕 網頁預覽功能按鈕

    2. 選取「變更通訊埠」,然後輸入 8083。瀏覽器視窗隨即開啟,並顯示類似下列的網址:

      https://8083-your-instance-id.cs-your-region.cloudshell.dev/?authuser=0
      
    3. 移除網址結尾的 ?authuser=0,並新增圖片檔案的路徑,例如 /images/fungi_frontier.jpg。範例如下:

      https://8083-your-instance-id.cs-your-region.cloudshell.dev/images/fungi_frontier.jpg
      

      瀏覽器中應該會顯示「Fungi Frontier」的封面圖片。

  6. 測試完成後,請停止容器以釋出資源:

    1. 列出正在執行的容器,並找出容器 ID:

      docker ps
      
    2. 停止每個容器:

      docker stop CONTAINER_ID
      

      CONTAINER_ID 替換為要停止的容器 ID。

將容器映像檔推送至 Artifact Registry

將應用程式部署至 Kubernetes 叢集前,必須先將容器映像檔儲存在叢集可存取的位置。在這個步驟中,您會將映像檔推送至先前建立的 Artifact Registry 存放區。在下一個教學課程中,您會將這些映像檔從 Artifact Registry 存放區部署到 GKE 叢集:

  1. 如要將容器映像檔推送至 Artifact Registry,請執行下列指令:

    docker push ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/home-app:${TAG}
    docker push ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-details-app:${TAG}
    docker push ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-reviews-app:${TAG}
    docker push ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/images-app:${TAG}
    
  2. 推送映像檔後,請列出映像檔,確認是否已成功上傳:

    gcloud artifacts docker images list ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}
    

    輸出結果應該會類似下列內容:

    Listing items under project ${PROJECT_ID}, location ${REPOSITORY_REGION}, repository ${REPOSITORY_NAME}.
    
    IMAGE: ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-details-app
    DIGEST: sha256:f7b78f44d70f2eedf7f7d4dc72c36070e7c0dd05daa5f473e1ebcfd1d44b95b1
    CREATE_TIME: 2024-11-14T00:38:53
    UPDATE_TIME: 2024-11-14T00:38:53
    SIZE: 52260143
    
    IMAGE: ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/book-reviews-app
    DIGEST: sha256:875ac8d94ef54db2ff637e49ad2d1c50291087623718b854a34ad657748fac86
    CREATE_TIME: 2024-11-14T00:39:04
    UPDATE_TIME: 2024-11-14T00:39:04
    SIZE: 52262041
    
    IMAGE: ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/home-app
    DIGEST: sha256:70ddc54ffd683e2525d87ee0451804d273868c7143d0c2a75ce423502c10638a
    CREATE_TIME: 2024-11-14T00:33:56
    UPDATE_TIME: 2024-11-14T00:33:56
    SIZE: 52262412
    
    IMAGE: ${REPOSITORY_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/images-app
    DIGEST: sha256:790f0d8c2f83b09dc3b431c4c04d7dc68254fecc76c48f00a83babc2a5dc0484
    CREATE_TIME: 2024-11-14T00:39:15
    UPDATE_TIME: 2024-11-14T00:39:15
    SIZE: 53020815
    

    輸出內容會顯示每張圖片的詳細資訊,如下所示:

    • IMAGE:存放區路徑和映像檔名稱。
    • 摘要:圖片的專屬 ID。
    • CREATE_TIME 或 UPDATE_TIME:圖片的建立時間或上次修改時間。
    • SIZE:圖片大小 (以位元組為單位)。

使用容器映像檔路徑更新 Kubernetes 資訊清單

如您在先前的教學課程「準備將模組化應用程式容器化」中所學,Kubernetes 資訊清單是 YAML 檔案,用於定義應用程式在 Kubernetes 叢集中的執行方式。包括下列詳細資料:

  • 應用程式的模組 (例如 home-appbook-details-app)
  • 容器映像檔的路徑
  • 設定詳細資料,例如資源限制
  • 在模組之間轉送要求的服務定義

在本節中,您會更新先前教學課程中查看的相同資訊清單檔案。該檔案為 kubernetes-manifest.yaml,內含圖片路徑的預留位置值。您需要將這些預留位置,替換為您在上一節中推送至 Artifact Registry 存放區的容器映像檔實際路徑。

如要更新 kubernetes-manifest.yaml Kubernetes 資訊清單檔案,請按照下列步驟操作:

  1. 在 Cloud Shell 中,前往 containerized/ 目錄,其中包含 Kubernetes 資訊清單檔案 kubernetes-manifest.yaml

    cd kubernetes-engine-samples/quickstarts/monolith-to-microservices/containerized/
    
  2. 在文字編輯器中開啟 kubernetes-manifest.yaml 檔案:

    vim kubernetes-manifest.yaml
    
  3. 找出含有預留位置的 image 欄位,例如:

    image: REPOSITORY_REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY_NAME/home-app:TAG
    

    將每個預留位置替換為您推送至 Artifact Registry 的容器映像檔實際路徑:

    完成這些取代作業後,路徑可能如下所示:

    image:us-west1-docker.pkg.dev/your-project-id/book-review-service-repo/home-app:v1
    
  4. 更新所有容器映像檔的路徑:

    • home-app
    • book-details-app
    • book-reviews-app
    • images-app
  5. 更新路徑後,請儲存資訊清單檔案並關閉編輯器。舉例來說,如果您使用 vim,請按下 Esc 鍵進入指令模式,輸入 wq,然後按下 Enter 鍵儲存並退出。

Kubernetes 資訊清單現已設定完畢,可將 Artifact Registry 存放區中的容器映像檔部署至 Kubernetes 叢集。

摘要

在本教學課程中,您已完成下列工作,為部署至 Kubernetes 叢集的模組化 Cymbal Books 應用程式做好準備:

  1. 設定專案,並為環境設定 Cloud Shell。 Google Cloud
  2. 查看每個應用程式模組的 Dockerfile。
  3. 使用 Docker 為應用程式模組建構容器映像檔。
  4. 在 Cloud Shell 中測試容器,確認功能正常運作。
  5. 將容器映像檔推送到 Artifact Registry 儲存。
  6. 更新 Kubernetes 資訊清單,使用 Artifact Registry 中的正確容器映像檔路徑。

後續步驟

在下一個教學課程「將應用程式部署至 GKE 叢集」中,您會將容器化應用程式部署至 GKE 叢集。