Linux中國

用 Kubernetes 和 Docker 部署 Java 應用

通過《面向 Java 開發者的 Kubernetes》,學習基本的 Kubernetes 概念和自動部署、維護和擴展你的 Java 應用程序的機制。下載該電子書的免費副本

在 《Java 的容器化持續交付》 中,我們探索了在 Docker 容器內打包和部署 Java 應用程序的基本原理。這只是創建基於容器的生產級系統的第一步。在真實的環境中運行容器還需要一個容器編排和計劃的平台,並且,現在已經存在了很多個這樣的平台(如,Docker Swarm、Apach Mesos、AWS ECS),而最受歡迎的是 KubernetesKubernetes 被用於很多組織的產品中,並且,它現在由原生雲計算基金會(CNCF)所管理。在這篇文章中,我們將使用以前的一個簡單的基於 Java 的電子商務商店,我們將它打包進 Docker 容器內,並且在 Kubernetes 上運行它。

「Docker Java Shopfront」 應用程序

我們將打包進容器,並且部署在 Kubernetes 上的 「Docker Java Shopfront」 應用程序的架構,如下面的圖所示:

在我們開始去創建一個所需的 Kubernetes 部署配置文件之前,讓我們先學習一下關於容器編排平台中的一些核心概念。

Kubernetes 101

Kubernetes 是一個最初由谷歌開發的開源的部署容器化應用程序的 編排器 orchestrator 。谷歌已經運行容器化應用程序很多年了,並且,由此產生了 Borg 容器編排器,它是應用於谷歌內部的,是 Kubernetes 創意的來源。如果你對這個技術不熟悉,一些出現的許多核心概念剛開始你會不理解,但是,實際上它們都很強大。首先, Kubernetes 採用了不可變的基礎設施的原則。部署到容器中的內容(比如應用程序)是不可變的,不能通過登錄到容器中做成改變。而是要以部署新的版本替代。第二,Kubernetes 內的任何東西都是 聲明式 declaratively 配置。開發者或運維指定系統狀態是通過部署描述符和配置文件進行的,並且,Kubernetes 是可以響應這些變化的——你不需要去提供命令,一步一步去進行。

不可變基礎設施和聲明式配置的這些原則有許多好處:它容易防止配置 偏移 drift ,或者 「 雪花 snowflake 」 應用程序實例;聲明部署配置可以保存在版本控制中,與代碼在一起;並且, Kubernetes 大部分都可以自我修復,比如,如果系統經歷失敗,假如是一個底層的計算節點失敗,系統可以重新構建,並且根據在聲明配置中指定的狀態去重新均衡應用程序。

Kubernetes 提供幾個抽象概念和 API,使之可以更容易地去構建這些分散式的應用程序,比如,如下的這些基於微服務架構的:

  • 豆莢 Pod —— 這是 Kubernetes 中的最小部署單元,並且,它本質上是一組容器。 豆莢 Pod 可以讓一個微服務應用程序容器與其它「挎斗」 容器,像日誌、監視或通訊管理這樣的系統服務一起被分組。在一個豆莢中的容器共享同一個文件系統和網路命名空間。注意,一個單個的容器也是可以被部署的,但是,通常的做法是部署在一個豆莢中。
  • 服務 —— Kubernetes 服務提供負載均衡、命名和發現,以將一個微服務與其它隔離。服務是通過複製控制器支持的,它反過來又負責維護在系統內運行期望數量的豆莢實例的相關細節。服務、複製控制器和豆莢在 Kubernetes 中通過使用「標籤」連接到一起,並通過它進行命名和選擇。

現在讓我們來為我們的基於 Java 的微服務應用程序創建一個服務。

構建 Java 應用程序和容器鏡像

在我們開始創建一個容器和相關的 Kubernetes 部署配置之前,我們必須首先確認,我們已經安裝了下列必需的組件:

  • 適用於 Mac / Windows / Linux 的 Docker - 這允許你在本地機器上,在 Kubernetes 之外去構建、運行和測試 Docker 容器。
  • Minikube - 這是一個工具,它可以通過虛擬機,在你本地部署的機器上很容易地去運行一個單節點的 Kubernetes 測試集群。
  • 一個 GitHub 帳戶和本地安裝的 Git - 示例代碼保存在 GitHub 上,並且通過使用本地的 Git,你可以復刻該倉庫,並且去提交改變到該應用程序的你自己的副本中。
  • Docker Hub 帳戶 - 如果你想跟著這篇教程進行,你將需要一個 Docker Hub 帳戶,以便推送和保存你將在後面創建的容器鏡像的拷貝。
  • Java 8 (或 9) SDK 和 Maven - 我們將使用 Maven 和附屬的工具使用 Java 8 特性去構建代碼。

從 GitHub 克隆項目庫代碼(可選,你可以 復刻 fork 這個庫,並且克隆一個你個人的拷貝),找到 「shopfront」 微服務應用: https://github.com/danielbryantuk/oreilly-docker-java-shopping/

$ git clone git@github.com:danielbryantuk/oreilly-docker-java-shopping.git
$ cd oreilly-docker-java-shopping/shopfront

請載入 shopfront 代碼到你選擇的編輯器中,比如,IntelliJ IDE 或 Eclipse,並去研究它。讓我們使用 Maven 來構建應用程序。最終生成包含該應用的可運行的 JAR 文件位於 ./target 的目錄中。

$ mvn clean install
…
[INFO] ---------------------------------------------------------------------[INFO] BUILD SUCCESS
[INFO] ---------------------------------------------------------------------[INFO] Total time: 17.210 s
[INFO] Finished at: 2017-09-30T11:28:37+01:00
[INFO] Final Memory: 41M/328M
[INFO] ---------------------------------------------------------------------

現在,我們將構建 Docker 容器鏡像。一個容器鏡像的操作系統選擇、配置和構建步驟,一般情況下是通過一個 Dockerfile 指定的。我們看一下,我們的示例中位於 shopfront 目錄中的 Dockerfile:

FROM openjdk:8-jre
ADD target/shopfront-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8010
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

第一行指定了,我們的容器鏡像將被 「 from 」 這個 openjdk:8-jre 基礎鏡像中創建。openjdk:8-jre 鏡像是由 OpenJDK 團隊維護的,並且包含了我們在 Docker 容器(就像一個安裝和配置了 OpenJDK 8 JDK的操作系統)中運行 Java 8 應用程序所需要的一切東西。第二行是,將我們上面構建的可運行的 JAR 「 添加 add 」 到這個鏡像。第三行指定了埠號是 8010,我們的應用程序將在這個埠號上監聽,如果外部需要可以訪問,必須要 「 暴露 exposed 」 它,第四行指定 「 入口 entrypoint 」 ,即當容器初始化後去運行的命令。現在,我們來構建我們的容器:

$ docker build -t danielbryantuk/djshopfront:1.0 .
Successfully built 87b8c5aa5260
Successfully tagged danielbryantuk/djshopfront:1.0

現在,我們推送它到 Docker Hub。如果你沒有通過命令行登入到 Docker Hub,現在去登入,輸入你的用戶名和密碼:

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username:
Password:
Login Succeeded
$
$ docker push danielbryantuk/djshopfront:1.0
The push refers to a repository [docker.io/danielbryantuk/djshopfront]
9b19f75e8748: Pushed 
...
cf4ecb492384: Pushed 
1.0: digest: sha256:8a6b459b0210409e67bee29d25bb512344045bd84a262ede80777edfcff3d9a0 size: 2210

部署到 Kubernetes 上

現在,讓我們在 Kubernetes 中運行這個容器。首先,切換到項目根目錄的 kubernetes 目錄:

$ cd ../kubernetes

打開 Kubernetes 部署文件 shopfront-service.yaml,並查看內容:

apiVersion: v1
kind: Service
metadata:
  name: shopfront
  labels:
    app: shopfront
spec:
  type: NodePort
  selector:
    app: shopfront
  ports:
  - protocol: TCP
    port: 8010
    name: http

apiVersion: v1
kind: ReplicationController
metadata:
  name: shopfront
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: shopfront
    spec:
      containers:
      - name: shopfront
        image: danielbryantuk/djshopfront:latest
        ports:
        - containerPort: 8010
        livenessProbe:
          httpGet:
            path: /health
            port: 8010
          initialDelaySeconds: 30
          timeoutSeconds: 1

這個 yaml 文件的第一節創建了一個名為 「shopfront」 的服務,它將到該服務(8010 埠)的 TCP 流量路由到標籤為 「app: shopfront」 的豆莢中 。配置文件的第二節創建了一個 ReplicationController ,其通知 Kubernetes 去運行我們的 shopfront 容器的一個複製品(實例),它是我們標為 「app: shopfront」 的聲明(spec)的一部分。我們也指定了暴露在我們的容器上的 8010 應用程序埠,並且聲明了 「livenessProbe」 (即健康檢查),Kubernetes 可以用於去決定我們的容器應用程序是否正確運行並準備好接受流量。讓我們來啟動 minikube 並部署這個服務(注意,根據你部署的機器上的可用資源,你可能需要去修 minikube 中的指定使用的 CPU 和 內存 memory ):

$ minikube start --cpus 2 --memory 4096
Starting local Kubernetes v1.7.5 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
$ kubectl apply -f shopfront-service.yaml
service "shopfront" created
replicationcontroller "shopfront" created

你可以通過使用 kubectl get svc 命令查看 Kubernetes 中所有的服務。你也可以使用 kubectl get pods 命令去查看所有相關的豆莢(注意,你第一次執行 get pods 命令時,容器可能還沒有創建完成,並被標記為未準備好):

$ kubectl get svc
NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
kubernetes   10.0.0.1     <none>        443/TCP          18h
shopfront    10.0.0.216   <nodes>       8010:31208/TCP   12s
$ kubectl get pods
NAME              READY     STATUS              RESTARTS   AGE
shopfront-0w1js   0/1       ContainerCreating   0          18s
$ kubectl get pods
NAME              READY     STATUS    RESTARTS   AGE
shopfront-0w1js   1/1       Running   0          2m

我們現在已經成功地在 Kubernetes 中部署完成了我們的第一個服務。

是時候進行煙霧測試了

現在,讓我們使用 curl 去看一下,我們是否可以從 shopfront 應用程序的健康檢查端點中取得數據:

$ curl $(minikube service shopfront --url)/health
{"status":"UP"}

你可以從 curl 的結果中看到,應用的 health 端點是啟用的,並且是運行中的,但是,在應用程序按我們預期那樣運行之前,我們需要去部署剩下的微服務應用程序容器。

構建剩下的應用程序

現在,我們有一個容器已經運行,讓我們來構建剩下的兩個微服務應用程序和容器:

$ cd ..
$ cd productcatalogue/
$ mvn clean install
…
$ docker build -t danielbryantuk/djproductcatalogue:1.0 .
...
$ docker push danielbryantuk/djproductcatalogue:1.0
...
$ cd ..
$ cd stockmanager/
$ mvn clean install
...
$ docker build -t danielbryantuk/djstockmanager:1.0 .
...
$ docker push danielbryantuk/djstockmanager:1.0
...

這個時候, 我們已經構建了所有我們的微服務和相關的 Docker 鏡像,也推送鏡像到 Docker Hub 上。現在,我們去在 Kubernetes 中部署 productcataloguestockmanager 服務。

在 Kubernetes 中部署整個 Java 應用程序

與我們上面部署 shopfront 服務時類似的方式去處理它,我們現在可以在 Kubernetes 中部署剩下的兩個微服務:

$ cd ..
$ cd kubernetes/
$ kubectl apply -f productcatalogue-service.yaml
service "productcatalogue" created
replicationcontroller "productcatalogue" created
$ kubectl apply -f stockmanager-service.yaml
service "stockmanager" created
replicationcontroller "stockmanager" created
$ kubectl get svc
NAME               CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE

kubernetes         10.0.0.1     <none>        443/TCP          19h
productcatalogue   10.0.0.37    <nodes>       8020:31803/TCP   42s
shopfront          10.0.0.216   <nodes>       8010:31208/TCP   13m
stockmanager       10.0.0.149   <nodes>       8030:30723/TCP   16s
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
productcatalogue-79qn4   1/1       Running   0          55s
shopfront-0w1js          1/1       Running   0          13m
stockmanager-lmgj9       1/1       Running   0          29s

取決於你執行 「kubectl get pods」 命令的速度,你或許會看到所有都處於不再運行狀態的豆莢。在轉到這篇文章的下一節之前,我們要等著這個命令展示出所有豆莢都運行起來(或許,這個時候應該來杯咖啡!)

查看完整的應用程序

在所有的微服務部署完成並且所有相關的豆莢都正常運行後,我們現在將去通過 shopfront 服務的 GUI 去訪問我們完整的應用程序。我們可以通過執行 minikube 命令在默認瀏覽器中打開這個服務:

$ minikube service shopfront

如果一切正常,你將在瀏覽器中看到如下的頁面:

結論

在這篇文章中,我們已經完成了由三個 Java Spring Boot 和 Dropwizard 微服務組成的應用程序,並且將它部署到 Kubernetes 上。未來,我們需要考慮的事還很多,比如,調試服務(或許是通過工具,像 TelepresenceSysdig),通過一個像 JenkinsSpinnaker 這樣的可持續交付的過程去測試和部署,並且觀察我們的系統運行。

本文是與 NGINX 協作創建的。 查看我們的編輯獨立性聲明.

作者簡介:

Daniel Bryant 是一名獨立技術顧問,他是 SpectoLabs 的 CTO。他目前關注於通過識別價值流、創建構建過程、和實施有效的測試策略,從而在組織內部實現持續交付。Daniel 擅長並關注於「DevOps」工具、雲/容器平台和微服務實現。他也貢獻了幾個開源項目,並定期為 InfoQ、 O』Reilly、和 Voxxed 撰稿...

via: https://www.oreilly.com/ideas/how-to-manage-docker-containers-in-kubernetes-with-java

作者:Daniel Bryant 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國