Kubernetes 教程第 1 部分:應用程序、微服務和容器

應我們的要求,Habr 創建了一個中心 Kubernetes 我們很高興將第一份出版物放入其中。 訂閱!

Kubernetes 很簡單。 為什麼銀行付給我很多錢讓我從事這個領域的工作,而任何人都可以在短短幾個小時內掌握這項技術?

Kubernetes 教程第 1 部分:應用程序、微服務和容器

如果你懷疑 Kubernetes 能學這麼快,我建議你自己嘗試一下。 也就是說,掌握了本材料後,您將能夠在 Kubernetes 集群中運行基於微服務的應用程序。 我可以保證這一點,因為我在這裡使用的方法與我教客戶如何使用 Kubernetes 的方法相同。 本指南與其他指南有何不同? 其實很多事情。 因此,這些材料中的大多數都是從簡單事物的解釋開始的 - Kubernetes 的概念和 kubectl 命令的功能。 這些文章的作者假設讀者熟悉應用程序開發、微服務和 Docker 容器。 我們會走另一條路。 首先,我們來談談如何在計算機上運行基於微服務的應用程序。 然後我們將研究為每個微服務構建容器映像。 之後,我們將熟悉 Kubernetes,並分析在 Kubernetes 管理的集群中基於微服務的應用程序的部署。

這種方法,以及對 Kubernetes 的漸進方法,將讓普通人深入了解正在發生的事情,以便了解 Kubernetes 中一切的安排是多麼簡單。 Kubernetes 當然是一項簡單的技術,只要想掌握它的人都知道它在哪里以及如何使用。

現在,事不宜遲,讓我們開始工作並討論我們將使用的應用程序。

實驗性應用程序

我們的應用程序將只執行一項功能。 它以一句話作為輸入,然後利用文本分析工具對這句話進行情感分析,獲得該句子的作者對某一對象的情感態度的評估。

這就是該應用程序的主窗口的樣子。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
情感分析 Web 應用程序

從技術角度來看,該應用程序由三個微服務組成,每個微服務解決一組特定的任務:

  • SA-Frontend 是一個 Nginx Web 服務器,提供 React 靜態文件。
  • SA-WebApp 是一個用 Java 編寫的 Web 應用程序,用於處理來自前端的請求。
  • SA-Logic 是一個執行文本情感分析的 Python 應用程序。

值得注意的是,微服務並不是孤立存在的。 他們貫徹了“職責分離”的思想,但同時,他們也需要彼此互動。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
應用程序中的數據流

在上圖中,您可以看到系統的編號階段,說明了應用程序中的數據流。 讓我們把它們分解一下:

  1. 瀏覽器向服務器請求文件 index.html (這又會加載 React 應用程序包)。
  2. 用戶與應用程序交互,這會導致調用基於 Spring 的 Web 應用程序。
  3. Web 應用程序將解析文本的請求轉發到 Python 應用程序。
  4. Python 應用程序分析文本的情緒並將結果作為對請求的響應返回。
  5. Spring 應用程序向 React 應用程序發送響應(反過來,React 應用程序向用戶顯示解析文本的結果)。

所有這些應用程序的代碼都可以找到 這裡。 我建議您立即將此存儲庫複製給自己,因為我們前面有許多有趣的實驗。

在本地機器上運行基於微服務的應用程序

為了使應用程序正常工作,我們需要啟動所有三個微服務。 讓我們從其中最漂亮的部分開始——前端應用程序。

▍設置 React 進行本地開發

為了運行 React 應用程序,您需要在計算機上安裝 Node.js 框架和 NPM。 安裝完所有這些後,使用終端進入項目文件夾 sa-frontend 並運行以下命令:

npm install

通過在文件夾中執行此命令 node_modules React應用程序的依賴項將被加載,其記錄在文件中 package.json。 將依賴項下載到同一文件夾後,運行以下命令:

npm start

就這樣。 React 應用程序現已運行,可以通過瀏覽器地址進行訪問 localhost:3000。 您可以更改他的代碼中的某些內容。 您將立即在瀏覽器中看到這些更改的效果。 這要歸功於所謂的模塊“熱”更換。 正因為如此,前端開髮變成了一種簡單而愉快的體驗。

▍為生產準備 React 應用程序

為了實際使用 React 應用程序,我們需要將其轉換為一組靜態文件,並使用 Web 服務器將它們提供給客戶端。

要構建 React 應用程序,請再次使用終端,導航到該文件夾 sa-frontend 並運行以下命令:

npm run build

這將在項目文件夾中創建一個目錄 build。 它將包含 React 應用程序工作所需的所有靜態文件。

▍使用 Nginx 提供靜態文件

首先,您需要安裝並運行 Nginx Web 服務器。 這裡 您可以下載它並找到安裝和運行它的說明。 然後需要復制該文件夾的內容 sa-frontend/build 到文件夾 [your_nginx_installation_dir]/html.

通過這種方法,在 React 應用程序的組裝過程中生成的文件 index.html 將於 [your_nginx_installation_dir]/html/index.html。 默認情況下,Nginx 服務器在訪問該文件時會發出該文件。 服務器配置為偵聽端口 80,但您可以通過編輯文件來自定義它 [your_nginx_installation_dir]/conf/nginx.conf.

現在打開瀏覽器並轉到 localhost:80。 您將看到 React 應用程序頁面。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
由 Nginx 服務器提供服務的 React 應用程序

如果您現在在字段中輸入內容 Type your sentence 並按下按鈕 Send - 什麼都不會發生。 但是,如果您查看控制台,您可以看到錯誤消息。 為了準確了解這些錯誤發生的位置,讓我們分析應用程序代碼。

▍前端應用程序代碼分析

查看文件的代碼 App.js,我們可以看到點擊按鈕 Send 調用一個方法 analyzeSentence()。 該方法的代碼如下所示。 同時,請注意每一行都有以下形式的註釋 # Номер,代碼下面給出了解釋。 以同樣的方式,我們將解析其他代碼片段。

analyzeSentence() {
    fetch('http://localhost:8080/sentiment', {  // #1
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
                       sentence: this.textField.getValue()})// #2
    })
        .then(response => response.json())
        .then(data => this.setState(data));  // #3
}

1. 發出 POST 請求的 URL。 假定該地址是等待此類請求的應用程序。

2.發送到應用程序的請求正文。 以下是請求正文示例:

{
    sentence: "I like yogobella!"
}

3.當接收到對請求的響應時,組件的狀態被更新。 這會導致組件重新渲染。 如果我們收到數據(即包含輸入數據和計算出的文本分數的 JSON 對象),我們將輸出組件 Polarity只要滿足條件。 我們是這樣描述該組件的:

const polarityComponent = this.state.polarity !== undefined ?
    <Polarity sentence={this.state.sentence} 
              polarity={this.state.polarity}/> :
    null;

該代碼似乎工作得很好。 無論如何,這裡出了什麼問題? 如果您假設在應用程序嘗試發送 POST 請求的地址處,還沒有任何東西可以接受和處理該請求,那麼您是絕對正確的。 即,處理到達該地址的請求 http://localhost:8080/sentiment,我們需要運行一個基於Spring的Web應用程序。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
我們需要一個可以接受 POST 請求的 Spring 應用程序

▍搭建基於Spring的Web應用

為了部署 Spring 應用程序,您需要 JDK8 和 Maven 以及正確配置的環境變量。 安裝完所有這些後,您可以繼續我們的項目。

▍將應用程序打包成jar文件

使用終端導航至文件夾 sa-webapp 並輸入以下命令:

mvn install

在文件夾中執行此命令後 sa-webapp 將創建目錄 target。 這是 Java 應用程序所在的位置,打包在 jar 文件中,由文件表示 sentiment-analysis-web-0.0.1-SNAPSHOT.jar.

▍啟動Java應用程序

轉到文件夾 target 並使用以下命令運行應用程序:

java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar

執行該命令時會發生錯誤。 為了開始修復它,我們可以解析堆棧跟踪數據中的異常詳細信息:

Error creating bean with name 'sentimentController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'sa.logic.api.url' in value "${sa.logic.api.url}"

對我們來說,這裡最重要的是提到無法澄清含義 sa.logic.api.url。 我們來分析一下發生錯誤的代碼。

▍Java應用程序代碼分析

這是發生錯誤的代碼片段。

@CrossOrigin(origins = "*")
@RestController
public class SentimentController {
    @Value("${sa.logic.api.url}")    // #1
    private String saLogicApiUrl;
    @PostMapping("/sentiment")
    public SentimentDto sentimentAnalysis(
        @RequestBody SentenceDto sentenceDto) 
    {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.postForEntity(
                saLogicApiUrl + "/analyse/sentiment",    // #2
                sentenceDto, SentimentDto.class)
                .getBody();
    }
}

  1. 在SentimentController 有一個字段 saLogicApiUrl。 它的值由屬性設置 sa.logic.api.url.
  2. 弦樂 saLogicApiUrl 與值連接 /analyse/sentiment。 它們一起形成一個地址,用於調用執行文本分析的微服務。

▍設置屬性值

在Spring中,屬性值的默認來源是文件 application.properties,可以在以下位置找到 sa-webapp/src/main/resources。 但使用它並不是設置屬性值的唯一方法。 您還可以使用以下命令執行此操作:

java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=WHAT.IS.THE.SA.LOGIC.API.URL

該屬性的值應指向我們的 Python 應用程序的地址。

通過配置它,我們告訴 Spring Web 應用程序需要去哪裡執行文本解析請求。

為了不讓我們的生活變得複雜,我們將決定 Python 應用程序將在以下位置提供: localhost:5000 並儘量不要忘記它。 因此,啟動 Spring 應用程序的命令將如下所示:

java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=http://localhost:5000

Kubernetes 教程第 1 部分:應用程序、微服務和容器
我們的系統缺少 Python 應用程序

現在我們只需運行 Python 應用程序,系統就會按預期工作。

▍設置Python應用程序

為了運行 Python 應用程序,您必須安裝 Python 3 和 Pip,並且必須正確設置相應的環境變量。

▍安裝依賴

轉到項目文件夾 sa-logic/sa 並運行以下命令:

python -m pip install -r requirements.txt
python -m textblob.download_corpora

▍應用程序啟動

安裝依賴項後,我們就可以運行應用程序了:

python sentiment_analysis.py

執行此命令後,我們將被告知以下內容:

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

這意味著應用程序正在運行並等待請求 localhost:5000/

▍代碼研究

讓我們看一下 Python 應用程序代碼,以了解它如何響應請求:

from textblob import TextBlob
from flask import Flask, request, jsonify
app = Flask(__name__)                                   #1
@app.route("/analyse/sentiment", methods=['POST'])      #2
def analyse_sentiment():
    sentence = request.get_json()['sentence']           #3
    polarity = TextBlob(sentence).sentences[0].polarity #4
    return jsonify(                                     #5
        sentence=sentence,
        polarity=polarity
    )
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)                #6

  1. 對像初始化 Flask.
  2. 指定向其發出 POST 請求的地址。
  3. 檢索屬性 sentence 來自請求正文。
  4. 匿名對像初始化 TextBlob 並獲取值 polarity 對於請求正文中收到的第一個提案(在我們的例子中,這是提交用於分析的唯一提案)。
  5. 返迴響應,其正文包含報價文本和為其計算的指標 polarity.
  6. 啟動 Flask 應用程序,該應用程序可在 0.0.0.0:5000 (您還可以使用以下形式的構造來訪問它 localhost:5000).

現在組成應用程序的微服務正在運行。 他們被設置為彼此互動。 這是此階段工作的應用程序圖的樣子。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
組成應用程序的所有微服務都處於健康狀態

現在,在我們繼續之前,在瀏覽器中打開 React 應用程序並嘗試用它解析一些句子。 如果一切都正確完成 - 按下按鈕後 Send 您將在文本框下方看到分析結果。

在下一節中,我們將討論如何在 Docker 容器中運行微服務。 為了準備應用程序在 Kubernetes 集群中運行,這是必要的。

Docker 容器

Kubernetes 是一個用於自動化容器化應用程序的部署、擴展和管理的系統。 它也被稱為“容器編排器”。 如果Kubernetes使用容器,那麼在使用這個系統之前,我們首先需要獲取這些容器。 但首先,我們來談談什麼是容器。 也許可以在其中找到它是什麼問題的最佳答案 文件 到 Docker:

容器鏡像是一個輕量級的、獨立的、可執行的包,其中包含一個應用程序,其中包括運行它所需的一切:應用程序代碼、運行時環境、系統工具和庫、設置。 容器化程序可以在 Linux 和 Windows 環境中使用,並且無論基礎設施如何,都將始終以相同的方式工作。

這意味著容器可以在任何計算機上運行,包括生產服務器,並且在任何環境中,其中包含的應用程序都將以相同的方式工作。

為了探索容器的功能並將其與其他運行應用程序的方式進行比較,讓我們看一下使用虛擬機和容器提供 React 應用程序的示例。

▍使用虛擬機提供 React 應用程序的靜態文件

嘗試使用虛擬機來組織靜態文件的維護,我們會遇到以下缺點:

  1. 資源利用效率低下,因為每個虛擬機都是一個完整的操作系統。
  2. 平台依賴性。 在某些本地計算機上有效的方法可能不適用於生產服務器。
  3. 虛擬機解決方案的緩慢且資源密集型擴展。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
Nginx Web 服務器提供在虛擬機中運行的靜態文件

如果使用容器來解決類似的問題,那麼與虛擬機相比,可以看出以下優勢:

  1. 資源的高效利用:使用Docker與操作系統一起工作。
  2. 平台獨立性。 開發人員可以在自己的計算機上運行的容器可以在任何地方運行。
  3. 通過使用鏡像層進行輕量級部署。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
Nginx Web 服務器提供在容器中運行的靜態文件

我們僅在幾個方面比較了虛擬機和容器,但即使這樣也足以了解容器的優勢。 這裡 您可以找到有關 Docker 容器的詳細信息。

▍為 React 應用構建容器鏡像

Docker 容器的基本構建塊是文件 Dockerfile。 在此文件的開頭,記錄了容器的基本映像,然後包含一系列指令,指示如何創建滿足應用程序需求的容器。

在我們開始使用該文件之前 Dockerfile,記住我們為了準備 React 應用程序的文件以上傳到 Nginx 服務器而做了什麼:

  1. 構建 React 應用程序包(npm run build).
  2. 啟動 Nginx 服務器。
  3. 複製目錄的內容 build 從項目文件夾 sa-frontend 到服務器文件夾 nginx/html.

下面您可以看到創建容器與在本地計算機上執行的上述操作之間的相似之處。

▍為 SA 前端應用程序準備 Dockerfile

須包含的說明 Dockerfile 申請 SA-Frontend,僅由兩支球隊組成。 事實上Nginx開發團隊已經準備好了一個基本的 圖片 對於 Nginx,我們將用它來構建我們的鏡像。 以下是我們需要描述的兩個步驟:

  1. 您需要將 Nginx 鏡像作為鏡像的基礎。
  2. 文件夾內容 sa-frontend/build 需要復製到圖片文件夾 nginx/html.

如果我們從這個描述轉到文件 Dockerfile,那麼它將如下所示:

FROM nginx
COPY build /usr/share/nginx/html

正如您所看到的,這裡的一切都非常簡單,而文件的內容甚至變得非常可讀和易於理解。 該文件告訴系統拍攝圖像 nginx 及其已有的所有內容,然後復制目錄的內容 build 到目錄 nginx/html.

在這裡您可能有一個關於我如何知道從文件夾中復製文件的確切位置的問題 build,即路徑從哪裡來 /usr/share/nginx/html。 事實上,這裡也沒有什麼複雜的。 事實上,相關信息可以在 描述 圖像。

▍組裝鏡像並上傳到存儲庫

在我們使用完成的圖像之前,我們需要將其提交到圖像存儲庫。 為此,我們將使用免費的基於雲的圖像託管平台 Docker Hub。 在這個階段的工作中,您需要完成以下工作:

  1. 建立 碼頭工人.
  2. 在 Docker Hub 站點上註冊。
  3. 通過在終端中運行以下命令來登錄您的帳戶:
    docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"

現在您需要使用終端轉到目錄 sa-frontend 並在那裡運行以下命令:

docker build -f Dockerfile -t $DOCKER_USER_ID/sentiment-analysis-frontend .

這里和下面的類似命令 $DOCKER_USER_ID 應替換為您在 Docker Hub 上的用戶名。 例如,這部分命令可能如下所示: rinormaloku/sentiment-analysis-frontend.

在這種情況下,可以通過從中刪除來縮短該命令 -f Dockerfile,因為我們執行此命令的文件夾已經有此文件。

為了將完成的圖像發送到存儲庫,我們需要以下命令:

docker push $DOCKER_USER_ID/sentiment-analysis-frontend

完成後,檢查 Docker Hub 上的存儲庫列表,看看鏡像是否已成功推送到雲存儲。

▍啟動容器

現在任何人都可以下載並運行名為 $DOCKER_USER_ID/sentiment-analysis-frontend。 為此,您需要運行以下命令序列:

docker pull $DOCKER_USER_ID/sentiment-analysis-frontend
docker run -d -p 80:80 $DOCKER_USER_ID/sentiment-analysis-frontend

現在容器正在運行,我們可以通過創建我們需要的其他鏡像來繼續工作。 但在我們繼續之前,讓我們先了解一下設計 80:80,它是在運行圖像的命令中找到的,可能看起來很混亂。

  • 第一個號碼 80 是主機(即本地計算機)的端口號。
  • 第二個號碼 80 是請求應重定向到的容器的端口。

考慮下圖。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
轉發端口

系統從端口轉發請求 <hostPort> 每個端口 <containerPort>。 也就是訪問端口 80 計算機被重定向到某個端口 80 容器。

自進港以來 80 在本地計算機上打開,您可以從此計算機訪問該應用程序 localhost:80。 如果您的系統不支持 Docker,您可以在 Docker 虛擬機上運行應用程序,其地址如下所示 <docker-machine ip>:80。 要找出Docker虛擬機的IP地址,可以使用命令 docker-machine ip.

此時,一旦前端應用程序容器成功啟動,您應該能夠在瀏覽器中打開其頁面。

▍.dockerignore 文件

構建應用程序映像 SA-Frontend,我們可以注意到這個過程非常慢。 這是因為鏡像構建上下文必鬚髮送到 Docker 守護進程。 表示構建上下文的目錄作為命令的最後一個參數給出 docker build。 在我們的例子中,該命令的末尾有一個點。 這會導致以下結構包含在程序集上下文中:

sa-frontend:
|   .dockerignore
|   Dockerfile
|   package.json
|   README.md
+---build
+---node_modules
+---public
---src

但在這裡的所有文件夾中,我們只需要一個文件夾 build。 下載其他任何東西都是浪費時間。 您可以通過告訴 Docker 忽略哪些目錄來加快構建速度。 為了做到這一點,我們需要一個文件 .dockerignore。 您,如果您熟悉該文件 .gitignore,這個文件的結構可能看起來很熟悉。 它列出了映像構建系統可以忽略的目錄。 在我們的例子中,該文件的內容如下所示:

node_modules
src
public

文件 .dockerignore 必須與文件位於同一文件夾中 Dockerfile。 現在圖像的組裝將需要幾秒鐘。

現在讓我們處理 Java 應用程序的圖像。

▍為Java應用程序構建容器鏡像

您知道嗎,並且您已經了解了創建容器映像所需的一切。 這就是為什麼本節會很短。

打開文件 Dockerfile,位於項目文件夾中 sa-webapp。 如果您閱讀此文件的文本,那麼在其中您只會遇到兩個以關鍵字開頭的新結構 ENV и EXPOSE:

ENV SA_LOGIC_API_URL http://localhost:5000
…
EXPOSE 8080

關鍵詞 ENV 允許您在 Docker 容器內聲明環境變量。 特別是,在我們的示例中,它允許您設置 URL 來訪問執行文本分析的應用程序的 API。

關鍵詞 EXPOSE 允許你告訴 Docker 打開一個端口。 我們將在使用應用程序時使用此端口。 在這裡你可以看到 Dockerfile 申請 SA-Frontend 沒有這樣的命令。 這僅用於文檔目的,換句話說,此構造是供讀者使用的 Dockerfile.

構建圖像並將其推送到存儲庫看起來與前面的示例完全相同。 如果你對自己的能力還不是很有信心,可以在文件中找到相應的命令 README.md 在文件夾中 sa-webapp.

▍為Python應用程序構建容器鏡像

如果你看一下文件的內容 Dockerfile 在文件夾中 sa-logic在那裡你不會發現任何新東西。 您應該已經熟悉用於構建映像並將其推送到存儲庫的命令,但是,就像我們的其他應用程序一樣,它們可以在文件中找到 README.md 在文件夾中 sa-logic.

▍測試容器化應用程序

你能相信一些你沒有測試過的東西嗎? 我也不能。 讓我們測試一下我們的容器。

  1. 讓我們啟動應用程序容器 sa-logic 並將其配置為偵聽端口 5050:
    docker run -d -p 5050:5000 $DOCKER_USER_ID/sentiment-analysis-logic
  2. 讓我們啟動應用程序容器 sa-webapp 並將其配置為偵聽端口 8080。 此外,我們需要通過重新分配環境變量來設置Python應用程序偵聽來自Java應用程序的請求的端口 SA_LOGIC_API_URL:
    $ docker run -d -p 8080:8080 -e SA_LOGIC_API_URL='http://<container_ip or docker machine ip>:5000' $DOCKER_USER_ID/sentiment-analysis-web-app

要了解如何查找容器或 Docker VM 的 IP 地址,請參閱文件 自述.

讓我們啟動應用程序容器 sa-frontend:

docker run -d -p 80:80 $DOCKER_USER_ID/sentiment-analysis-frontend

現在一切準備就緒,可以在瀏覽器中導航到該地址 localhost:80 並測試該應用程序。

請注意,如果您更改端口 sa-webapp,或者如果您正在運行 Docker VM,則需要編輯該文件 App.js 從文件夾中 sa-frontend通過更改方法中的IP地址或端口號 analyzeSentence()通過替換當前信息而不是過時的數據。 之後,您需要重新組裝圖像並使用它。

這就是我們的應用程序圖現在的樣子。

Kubernetes 教程第 1 部分:應用程序、微服務和容器
微服務在容器中運行

總結:為什麼需要 Kubernetes 集群?

我們剛剛審查了文件 Dockerfile,討論瞭如何構建鏡像並將其推送到 Docker 存儲庫。 此外,我們還學習瞭如何使用該文件加速圖像的組裝 .dockerignore。 因此,我們的微服務現在運行在 Docker 容器中。 在這裡你可能有一個完全合理的問題:為什麼我們需要 Kubernetes。 這個問題的答案將集中在本材料的第二部分。 同時,請考慮以下問題:
假設我們的文本分析 Web 應用程序已在全球範圍內流行。 每分鐘都有數以百萬計的請求向他提出。 這意味著微服務 sa-webapp и sa-logic 將會承受巨大的壓力。 如何擴展運行微服務的容器?

Kubernetes 教程第 1 部分:應用程序、微服務和容器

來源: www.habr.com

添加評論