開發適用於 Azure SQL 資料庫的 Kubernetes 應用程式

適用於:Azure SQL 資料庫

在本教學課程中,瞭解如何使用 Python、Docker 容器、Kubernetes 和 Azure SQL 資料庫來開發新式應用程式。

新式應用程式開發有數個挑戰。 從選取前端的「堆疊」到資料儲存和處理,從多個競爭標準到確保最高層級的安全性和效能,開發人員都必須確保應用程式具有良好擴展性並正常執行,且可在多個平台上提供支援。 針對最後一項需求,將應用程式統合到 Docker 等容器技術,並將多個容器部署到 Kubernetes 平台,如今已成為應用程式開發中的標準做法。

在此範例中,我們會探索使用 Python、Docker 容器和 Kubernetes - 全部都在 Microsoft Azure 平台上執行。 使用 Kubernetes 表示您也可以彈性地使用本機環境,甚至是其他雲端,以順暢且一致地部署應用程式,並允許多重雲端部署,以達到更高的復原能力。 我們也會針對以服務為基礎、可調整、高度復原且安全的環境使用 Microsoft Azure SQL 資料庫,以用於資料儲存和處理。 事實上,在許多情況下,其他應用程式通常會使用 Microsoft Azure SQL 資料庫,而且此範例應用程式可用來進一步使用和擴充該資料。

此範例的範圍相當全面,但會使用最簡單的應用程式、資料庫和部署來說明流程。 您可以調整此範例,使其更強固,即使是使用傳回資料的最新技術也一樣。 這是為其他應用程式建立模式的實用學習工具。

在實際範例中使用 Python、Docker 容器、Kubernetes 和 AdventureWorksLT 範例資料庫

AdventureWorks (虛構) 公司使用資料庫來儲存有關銷售與行銷、產品、客戶和製造的資料。 它也包含加入產品相關資訊的檢視和預存程序,例如產品名稱、類別、價格和簡短描述。

AdventureWorks 開發小組想要建立概念證明 (PoC),以從 AdventureWorksLT 資料庫中的檢視傳回資料,並讓資料以 REST API 的形式提供。 使用此 PoC,開發團隊會為銷售團隊建立更可調整和多雲端就緒的應用程式。 他們已針對部署的所有層面選取 Microsoft Azure 平台。 此 PoC 使用下列元素:

  • 使用 Flask 套件進行無周邊 Web 部署的 Python 應用程式。
  • 適用於程式碼和環境隔離的 Docker 容器,儲存在私人登錄中,讓整個公司可以在未來專案中重複使用應用程式容器,以節省時間和金錢。
  • Kubernetes 可讓您輕鬆部署和調整規模,並避免被鎖定僅能使用特定平台。
  • 除了最高安全性層級的關聯式資料儲存和處理之外,Microsoft Azure SQL 資料庫可選取大小、效能、縮放、自動管理及備份。

在本文中,我們會說明建立整個概念證明專案的程式。 建立應用程式的一般步驟如下:

  1. 設定必要條件
  2. 建立應用程式
  3. 建立 Docker 容器以部署應用程式並測試
  4. 建立 Azure Container Service (ACS) 登錄,並將容器載入 ACS 登錄
  5. 建立 Azure Kubernetes Service (AKS) 環境
  6. 將應用程式容器從 ACS 登錄部署到 AKS
  7. 測試應用程式
  8. 清理

必要條件

在本文中,有幾個您應該取代的值。 請確定您一致地取代每個步驟的這些值。 您可能會想要開啟文字編輯器,並卸除這些值,以在您完成概念證明專案時設定正確的值:

  • ReplaceWith_AzureSubscriptionName:將此值取代為您擁有的 Azure 訂用帳戶名稱。
  • ReplaceWith_PoCResourceGroupName:以您想建立之資源群組名稱取代此值。
  • ReplaceWith_AzureSQLDBServerName:以您使用 Azure 入口網站 建立之 Azure SQL 資料庫邏輯伺服器名稱取代此值。
  • ReplaceWith_AzureSQLDBSQLServerLoginName:以您在 Azure 入口網站中建立之 SQL Server 使用者名稱值取代此值。
  • ReplaceWith_AzureSQLDBSQLServerLoginPassword:以您在 Azure 入口網站中建立之 SQL Server 使用者密碼值取代此值。
  • ReplaceWith_AzureSQLDBDatabaseName:以您使用 Azure 入口網站 建立之 Azure SQL 資料庫名稱取代此值。
  • ReplaceWith_AzureContainerRegistryName:將此值取代為您想要建立的 Azure Container Registry 名稱。
  • ReplaceWith_AzureKubernetesServiceName:將此值取代為您想要建立的 Azure Kubernetes Service 名稱。

AdventureWorks 的開發人員混合使用 Windows、Linux 和 Apple 系統進行開發,因此他們使用 Visual Studio Code 作為其環境和 Git 進行原始檔控制,這兩者都會跨平台執行。

針對 PoC,團隊需要下列必要條件:

  1. Python、pip 和套件 - 開發團隊選擇 Python 程式設計語言作為此網頁型應用程式的標準。 他們目前使用 3.9 版,但支援 PoC 必要套件的任何版本都是可接受的。

  2. 該團隊使用 pyodbc 套件存取資料庫。

  3. 團隊會使用 ConfigParser 套件來控制和設定組態變數。

  4. 團隊會針對應用程式的網頁介面使用 Flask 套件

  5. 接下來,團隊會安裝 Azure CLI 工具,透過 az 語法很輕鬆地就能識別。 此跨平台工具允許使用命令行和指令碼化方法進行 PoC,讓他們能在進行變更和改進時重複這些步驟。

  6. 設定好 Azure CLI 之後,團隊會登入其 Azure 訂用帳戶,並設定用於 PoC 的訂用帳戶名稱。 然後,他們可確保 Azure SQL 資料庫伺服器和資料庫可供訂用帳戶存取:

    az login
    az account set --name "ReplaceWith_AzureSubscriptionName"
    az sql server list
    az sql db list ReplaceWith_AzureSQLDBDatabaseName 
    
  7. Microsoft Azure 資源群組是保留 Azure 解決方案相關資源的邏輯容器。 一般而言,共用相同生命週期的資源會新增至相同的資源群組,以便您輕鬆地以群組的形式部署、更新和刪除資源。 資源群組會儲存資源的相關中繼資料,而且您可以指定資源群組的位置。

    資源群組可以使用 Azure 入口網站或 Azure CLI 來建立和管理。 它們也可以用來將應用程式的相關資源分組,並將其分成生產和非生產環境的群組,或您偏好的任何其他組織結構。

    Azure 入口網站顯示如何搜尋資源群組的螢幕擷取畫面。

    在下列程式碼片段中,您可以看到 az 用來建立資源群組的命令。 在我們的範例中,我們使用 Azure 的 eastus 區域

    az group create --name ReplaceWith_PoCResourceGroupName --location eastus
    
  8. 開發團隊會使用 SQL 驗證登入,建立已安裝 AdventureWorksLT 範例資料庫的 Azure SQL 資料庫。

    AdventureWorks 已在 Microsoft SQL Server 關聯式資料庫管理系統平台上標準化,而開發團隊想要針對資料庫使用受控服務,而不是在本機安裝。 使用 Azure SQL 資料庫可讓此受控服務在執行 SQL Server 引擎時完全相容:內部部署、在容器、Linux 或 Windows 中,甚至是在物聯網 (IoT) 環境中。

    1. 在建立期間,他們使用 Azure 管理入口網站將應用程式的防火牆設定為本機開發機器,並變更您在此處看到的預設值,以啟用 [允許所有 Azure 服務],並擷取連線認證

      顯示 [建立 SQL Database] 頁面 Azure 入口網站 的螢幕擷取畫面。在 [網路] 索引標籤的 [連線方法] 中,已選取 [公用端點] 選項。[新增目前的用戶端 IP 位址] 選項為 [是]。

      使用此方法,資料庫可以在另一個區域或甚至是不同的訂用帳戶中存取。

    2. 團隊會設定 SQL 驗證登入進行測試,但會在安全性檢閱中重新審視此決策。

    3. 團隊使用相同的 PoC 資源群組,針對 PoC 使用範例 AdventureWorksLT 資料庫。 別擔心,在本教學課程結束時,我們將清除這個新 PoC 資源群組中的所有資源。

    4. 您可以使用 Azure 入口網站部署 Azure SQL 資料庫。 建立 Azure SQL 資料庫時,請在 [其他設定] 索引標籤的 [使用現有資料] 選項中,選取 [範例]。

      來自 Azure 入口網站的螢幕擷取畫面,展示出 [建立 SQL 資料庫頁面]。在 [其他設定] 索引標籤的 [使用現有資料] 選項中,選取 [範例]。

    5. 最後,在新 Azure SQL 資料庫的 [標籤] 索引標籤上,開發團隊提供此 Azure 資源的標籤中繼資料,例如擁有者服務類別工作負責名稱

建立應用程式

接下來,開發團隊建立了簡單的 Python 應用程式,以開啟與 Azure SQL 資料庫的連線,並傳回產品清單。 此程式碼會被更複雜函式取代,而且可能包含在生產環境中部署至 Kubernetes Pod 的多個應用程式,以為應用程式解決方案提供強固且以資訊清單驅動的方法。

  1. 該團隊建立了名為 .env 的簡單文字檔,以儲存伺服器連線的變數和其他資訊。 接著,他們可以使用連結 python-dotenv 庫,將變數與 Python 程式碼區隔開。 這是將祕密和其他資訊保存在程式碼本身的常見方法。

    SQL_SERVER_ENDPOINT = ReplaceWith_AzureSQLDBServerName
    SQL_SERVER_USERNAME = ReplaceWith_AzureSQLDBSQLServerLoginName
    SQL_SERVER_PASSWORD = ReplaceWith_AzureSQLDBSQLServerLoginPassword
    SQL_SERVER_DATABASE = ReplaceWith_AzureSQLDBDatabaseName
    

    警告

    為了清楚且簡單起見,此應用程式會使用從 Python 讀取的組態檔。 由於程式碼會使用容器部署,因此連線資訊可能會從容器內容衍生出來。 您應該仔細考慮使用安全性、連線和祕密的各種方法,並判斷您應該用於應用程式的最佳層級和機制。 請一律挑選最高層級的安全性,甚至是多個層級,以確保您的應用程式安全無虞。 您有多個選項可處理祕密資訊,例如連接字串等,下列清單會顯示其中一些選項。

    如需詳細資訊,請參閱 Azure SQL 資料庫安全性

  2. 團隊接下來撰寫了 PoC 應用程式,並稱它為 app.py

    下列指令碼會完成這些步驟:

    1. 設定組態和基底網頁介面的程式庫。
    2. .env 檔案載入變數。
    3. 建立 Flask-RESTful 應用程式。
    4. 使用 config.ini 檔案值取得 Azure SQL 資料庫連線資訊。
    5. 使用 config.ini 檔案值建立與 Azure SQL 資料庫的連線。
    6. 使用 pyodbc 套件連線至 Azure SQL 資料庫。
    7. 建立針對資料庫執行的 SQL 查詢。
    8. 建立用於從 API 傳回資料的類別。
    9. 將 API 端點設定為 Products 類別。
    10. 最後,在預設 Flask 連接埠 5000 上啟動應用程式。
    # Set up the libraries for the configuration and base web interfaces
    from dotenv import load_dotenv
    from flask import Flask
    from flask_restful import Resource, Api
    import pyodbc
    
    # Load the variables from the .env file
    load_dotenv()
    
    # Create the Flask-RESTful Application
    app = Flask(__name__)
    api = Api(app)
    
    # Get to Azure SQL Database connection information using the config.ini file values
    server_name = os.getenv('SQL_SERVER_ENDPOINT')
    database_name = os.getenv('SQL_SERVER_DATABASE')
    user_name = os.getenv('SQL_SERVER_USERNAME')
    password = os.getenv('SQL_SERVER_PASSWORD')
    
    # Create connection to Azure SQL Database using the config.ini file values
    ServerName = config.get('Connection', 'SQL_SERVER_ENDPOINT')
    DatabaseName = config.get('Connection', 'SQL_SERVER_DATABASE')
    UserName = config.get('Connection', 'SQL_SERVER_USERNAME')
    PasswordValue = config.get('Connection', 'SQL_SERVER_PASSWORD')
    
    # Connect to Azure SQL Database using the pyodbc package
    # Note: You may need to install the ODBC driver if it is not already there. You can find that at:
    # https://video2.skills-academy.com/sql/connect/odbc/download-odbc-driver-for-sql-server
    connection = pyodbc.connect(f'Driver=ODBC Driver 17 for SQL Server;Server={ServerName};Database={DatabaseName};uid={UserName};pwd={PasswordValue}')
    
    # Create the SQL query to run against the database
    def query_db():
        cursor = connection.cursor()
        cursor.execute("SELECT TOP (10) [ProductID], [Name], [Description] FROM [SalesLT].[vProductAndDescription] WHERE Culture = 'EN' FOR JSON AUTO;")
        result = cursor.fetchone()
        cursor.close()
        return result
    
    # Create the class that will be used to return the data from the API
    class Products(Resource):
        def get(self):
            result = query_db()
            json_result = {} if (result == None) else json.loads(result[0])     
            return json_result, 200
    
    # Set the API endpoint to the Products class
    api.add_resource(Products, '/products')
    
    # Start App on default Flask port 5000
    if __name__ == "__main__":
        app.run(debug=True)
    
  3. 他們會檢查此應用程式是否在本機執行,並將頁面傳回至 http://localhost:5000/products

    Flask 退回頁面網頁瀏覽器的螢幕擷取畫面。

    重要

    建置生產應用程式時,請勿使用系統管理員帳戶來存取資料庫。 如需詳細資訊,請閱讀如何為應用程式設定帳戶的詳細資訊。 本文中的程式碼已簡化,讓您可以在 Azure 中使用 Python 和 Kubernetes 快速開始使用應用程式。

    更現實地,您可以使用具有唯讀權限的自主資料庫使用者,或使用唯讀權限連線到使用者指派的受控識別的登入或自主資料庫使用者。

    如需詳細資訊,請檢閱如何使用 Python 和 Azure SQL 資料庫建立 API 的完整範例

將應用程式部署至 Docker 容器應用程式

容器是運算系統中保留且受保護的空間,可提供隔離和封裝。 若要建立容器,請使用資訊清單檔案,它只是描述您想包含之二進位檔和程式碼的文字檔。 使用容器執行階段 (例如 Docker),您接著可以建立二進位映像,其中包含您想要執行和參考的所有檔案。 在這裡,您可以「執行」二進位映像,這稱為「容器」,您可以將其當成完整運算系統一樣來參考。 相較於使用完整的虛擬機器,容器是更小巧、更簡單的抽象化應用程式執行階段和環境的方法。 如需詳細資訊,請參閱控制器和 Docker

該團隊從 DockerFile (資訊清單) 開始,將該團隊想要使用的元素分層。 他們從已安裝 pyodbc 程式庫的基底 Python 映像開始,然後執行包含上一個步驟中程序與組態檔所需的所有命令。

下列 Dockerfile 具有下列步驟:

  1. 從已安裝 Python 和 pyodbc 的容器二進位檔開始。
  2. 建立應用程式的工作目錄。
  3. 將所有程式碼從目前目錄複製到 WORKDIR
  4. 安裝必要的程式庫。
  5. 容器啟動之後,執行應用程式,並開啟所有 TCP/IP 連接埠。
# syntax=docker/dockerfile:1

# Start with a Container binary that already has Python and pyodbc installed
FROM laudio/pyodbc

# Create a Working directory for the application
WORKDIR /flask2sql

# Copy all of the code from the current directory into the WORKDIR
COPY . .

# Install the libraries that are required
RUN pip install -r ./requirements.txt

# Once the container starts, run the application, and open all TCP/IP ports 
CMD ["python3", "-m" , "flask", "run", "--host=0.0.0.0"]

在該檔案就緒後,團隊卸除至程式碼目錄中的命令提示字元,然後執行下列程式碼,以從資訊清單建立二進位映像,然後執行另一個命令以啟動容器:

docker build -t flask2sql .
docker run -d -p 5000:5000 -t flask2sql

團隊再次測試 http://localhost:5000/products 連結,以確保容器可以存取資料庫,並看到下列傳回:

來自容器之 Flask 退回頁面網頁瀏覽器的螢幕擷取畫面。

將映像部署至 Docker 登錄

容器現已運作,但只能在開發人員的機器上使用。 開發團隊想要讓此應用程式映像可供公司其餘部門使用,然後移至 Kubernetes 以進行生產環境部署。

容器映像的儲存區域稱為存放庫,而且容器映像可以同時有公用和私人存放庫。 事實上,AdvenureWorks 在其 Dockerfile 中使用了 Python 環境的公用映像。

該團隊想要控制映像的存取權,於是決定自己託管映像,而不是將它放在網路上,但在 Microsoft Azure 中,他們可以完全控制安全性和存取權。 您可以在這裡深入瞭解 Microsoft Azure Container Registry。

返回命令行時,該開發團隊使用 az CLI 來新增容器登錄服務、啟用系統管理帳戶、在測試階段將它設定為匿名「接收」,並將登入內容設定至登錄:

az acr create --resource-group ReplaceWith_PoCResourceGroupName --name ReplaceWith_AzureContainerRegistryName --sku Standard
az acr update -n ReplaceWith_AzureContainerRegistryName --admin-enabled true
az acr update --name ReplaceWith_AzureContainerRegistryName --anonymous-pull-enabled
az acr login --name ReplaceWith_AzureContainerRegistryName

後續步驟會使用此內容。

標記本機 Docker 映像以準備上傳

下一個步驟是將本機應用程式容器映像傳送至 Azure Container Registry (ACR) 服務,使其可在雲端中使用。

  1. 在下列範例指令碼中,該團隊使用 Docker 命令來列出電腦上的映像。
  2. 他們使用 az CLI 公用程式來列出 ACR 服務中的映像。
  3. 他們使用 Docker 命令,使用在上一個步驟中建立的 ACR 目的地名稱「標記」映像,並為進行適當的 DevOps 設定版本號碼。
  4. 最後,他們再次列出本機映像資訊,以確保已正確套用標記。
docker images
az acr list --resource-group ReplaceWith_PoCResourceGroupName --query "[].{acrLoginServer:loginServer}" --output table
docker tag flask2sql ReplaceWith_AzureContainerRegistryName.azurecr.io/azure-flask2sql:v1
docker images

在撰寫並測試程式碼,執行並測試 Dockerfile、映像和容器、設定 ACR 服務設定並套用所有標記讓,該團隊就可以將映像上傳至 ACR 服務。

他們使用 Docker “push” 命令來傳送檔案,然後使用 az CLI 公用程式以確保已載入映像:

docker push ReplaceWith_AzureContainerRegistryName.azurecr.io/azure-flask2sql:v1
az acr repository list --name ReplaceWith_AzureContainerRegistryName --output table

部署至 Kubernetes

該團隊只需執行容器,並將應用程式部署至內部部署和雲端環境。 不過,他們想要新增應用程式的多個複本以調整和可用性、新增其他執行不同工作的容器,以及將監視和檢測設備新增至整個解決方案。

為了將容器分組在一起成完整的解決方案,該團隊決定使用 Kubernetes。 Kubernetes 會在內部部署和所有主要雲端平台中執行。 Microsoft Azure 有完整的 Kubernetes 受控環境,稱為 Azure Kubernetes Service (AKS)。 透過 Azure 訓練路徑上的 Kubernetes 簡介,深入瞭解 AKS。

該團隊使用 az CLI 公用程式,將 AKS 新增至他們稍早建立的相同資源群組。 使用單一 az 命令,開發團隊完成下列步驟:

  • 在測試階段新增兩個「節點」或運算環境以取得復原能力
  • 自動產生 SSH 金鑰以存取環境
  • 附加他們在先前步驟中建立的 ACR 服務,讓 AKS 叢集可以找到想要用於部署的映像
az aks create --resource-group ReplaceWith_PoCResourceGroupName --name ReplaceWith_AzureKubernetesServiceName --node-count 2 --generate-ssh-keys --attach-acr ReplaceWith_AzureContainerRegistryName

Kubernetes 會使用命令行工具來存取和控制稱為 kubectl 的叢集。 該團隊使用 az CLI 公用程式來下載 kubectl 工具並加以安裝:

az aks install-cli

由於他們此時已連線到 AKS,因此可以要求 AKS 傳送連線的 SSH 金鑰,以便在執行 kubectl 公用程式時使用:

az aks get-credentials --resource-group ReplaceWith_PoCResourceGroupName --name ReplaceWith_AzureKubernetesServiceName

這些金鑰會儲存在使用者目錄中名為 .config 的檔案中。 在該安全性內容集中,該團隊使用 kubectl get nodes 來顯示叢集中的節點:

kubectl get nodes

現在該團隊使用 az CLI 工具來列出 ACR 服務中的映像:

az acr list --resource-group ReplaceWith_PoCResourceGroupName --query "[].{acrLoginServer:loginServer}" --output table

現在,他們可以建置 Kubernetes 用來控制部署的資訊清單。 這是以 yaml 格式儲存的文字檔。 以下是 flask2sql.yaml 檔案中的已標註文字:

apiVersion: apps/v1
# The type of commands that will be sent, along with the name of the deployment
kind: Deployment
metadata:
  name: flask2sql
# This section sets the general specifications for the application
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask2sql
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5 
  template:
    metadata:
      labels:
        app: flask2sql
    spec:
      nodeSelector:
        "kubernetes.io/os": linux
# This section sets the location of the Image(s) in the deployment, and where to find them 
      containers:
      - name: flask2sql
        image:  bwoodyflask2sqlacr.azurecr.io/azure-flask2sql:v1
# Recall that the Flask application uses (by default) TCIP/IP port 5000 for access. This line tells Kubernetes that this "pod" uses that address.
        ports:
        - containerPort: 5000
---
apiVersion: v1
# This is the front-end of the application access, called a "Load Balancer"
kind: Service
metadata:
  name: flask2sql
spec:
  type: LoadBalancer
# this final step then sets the outside exposed port of the service to TCP/IP port 80, but maps it internally to the app's port of 5000
  ports:
  - protocol: TCP
    port: 80
    targetPort: 5000
  selector:
    app: flask2sql

定義 flask2sql.yaml 檔案後,該團隊就可以將應用程式部署至執行中的 AKS 叢集。 這是使用 kubectl apply 命令完成的,因為您記得叢集仍有安全性內容。 然後,傳送 kubectl get service 命令以監看正在建置的叢集。

kubectl apply -f flask2sql.yaml
kubectl get service flask2sql --watch

幾分鐘後,“watch” 命令會傳回外部 IP 位址。 此時,團隊按 CTRL-C 來中斷監看命令,並記錄負載平衡器的外部 IP 位址。

測試應用程式

團隊該使用他們在最後一個步驟中取得的IP位址 (端點)來檢查以確保與本機應用程式和 Docker 容器相同的輸出:

最後測試容器時,Flask 退回頁面網頁瀏覽器的螢幕擷取畫面。輸出與之前相同。

清理

在建立、編輯、記錄和測試應用程式之後,該團隊現在可以「卸除」應用程式。 藉由在 Microsoft Azure 中的單一資源群組中保留所有內容,只需使用 az CLI 公用程式刪除 PoC 資源群組即可:

az group delete -n ReplaceWith_PoCResourceGroupName -y

注意

如果您在另一個資源群組中建立 Azure SQL 資料庫,而不再需要它,您可以使用 Azure 入口網站將其刪除。

領導 PoC 專案的團隊成員使用 Microsoft Windows 作為其工作站,並想要保留 Kubernetes 的祕密檔案,但將其從系統移除作為使用中位置。 他們可以直接將檔案複製到 config.old 文字檔,然後加以刪除:

copy c:\users\ReplaceWith_YourUserName\.kube\config c:\users\ReplaceWith_YourUserName\.kube\config.old
del c:\users\ReplaceWith_YourUserName\.kube\config