微服務架構在Kubernetes上的實現
我們討論了最近的微服務趨勢,以及伴隨微服務架構可能出現的一些複雜問題。在接下來的幾周內,我們將深入探討這個問題。我們將探討不同設計選擇中固有的權衡,以及可以採取哪些措施來緩解這些問題。
然而,在深入之前,我認為花一點時間來了解當今微服務中的最新技術狀態是有意義的。我們首先回顧一下領先的容器管理和服務編排框架Kubernetes。 如今,Kubernetes和微服務幾乎是同義詞,所以最好徹底瞭解它們是如何組合在一起的。
Kubernetes
與微服務本身非常相似,容器近年來已成為現代可擴充套件架構中不可或缺的一部分。與微服務一樣,容器已經流行起來,因為它們為開發過程提供了真正的好處:它們可靠,易於擴充套件,並提供了一個很好的抽象,隔離了Web服務的核心元件。
特別是,一種容器化技術已遠遠超過其他技術。 這是正確的,我們的微服務之旅的下一站是看看Kubernetes和Docker,它是現代微服務設施的主力。簡單地說,Kubernetes是現代基於容器的DevOps和微服務以及容器攜手並進的黃金標準。
隨著容器化技術的興起,有幾種競爭技術可用於管理大型Docker部署和基於容器的服務。你可能還記得其中一些退役的解決方案:Docker Swarm,Apache Mesos,OpenStack Magnum等。然而,現在Kubernetes已經淘汰了競爭對手。它是唯一的AWS,Azure,Google Cloud原生自帶,同時RedHat和Pivotal等許多私有云供應商也提供的容器化解決方案。
Kubernetes能夠如此迅速地獲得如此多的優勢,根因在於它能夠將配置與編排分開。這種複雜程度應該不足為奇,因為Kubernetes來自谷歌的內部專案Borg,它是谷歌在分散式系統上的數十年經驗總結。使用Kubernetes,你可以指定服務的外觀,例項數,冗餘型別,服務所在位置。然後,該工具自動計算從現狀到建立該服務需要進行哪些更改。可以把它想象成SQL,你沒有指定資料庫如何新增或轉換每個行。你可以指定資料的外觀,資料庫會指出如何實現資料。 Kubernetes也是一樣的。
Kubernetes特點
Kubernetes提供的是將容器視為服務定義的能力。Kubernetes可以處理純容器。即使你想在不進入微服務領域的情況下只部署容器,Kubernetes在管理和部署方面也能為你提供很多幫助。你在群集中的伺服器上安裝Kubernetes軟體,Kubernetes主程序將自動部署你的軟體。
除了基本的容器外,Kubernetes還可以使用它所稱的Pod。 Pod是由一個或多個服務組成的單獨定義。 Pod可以包含從單獨執行的單個伺服器到完整的多容器服務,例如資料庫容器與鍵值儲存和一個包含在一起的http伺服器相結合。 Pod是Kubernetes的基本構建塊。
最後一個元素是服務。在Kubernetes中,服務就像是將Pod組合到應用程式中的配方。雖然Pod是具有生命週期的具體部署,但服務更抽象。它描述了一個單獨的元件,如後端或資料庫。
結合所有這些能力的是Kubernetes命令列工具kubectl。雖然Kubernetes提供的抽象很棒,但命令列工具非常強大,允許你使用kubectl命令描述對架構的複雜更改。總而言之,kubectl CLI工具包含近50種不同的命令,用於處理在修改基於容器的微服務部署過程中出現的所有情況(你總會出現出錯的時候)。
動手實踐一番
雖然高層次描述很有幫助,但實際上沒有什麼比實際部署Kubernetes服務能更好的理解它的了。我們在這裡沒有做任何高深的東西,只是展示如何部署一個簡單的“Hello World”服務,但它應該是有益的。
我們在Go中編寫了一個簡單的伺服器,用“Hello World”響應http請求。程式碼非常簡單:
package mainimport("fmt""log""net/http""os")funchandler(w http.ResponseWriter, r *http.Request){log.Print("Hello world received a request.")version := os.Getenv("VERSION")ifversion ==""{ version ="v1"}log.Println(version)fmt.Fprintf(w,"Hello world %s\n",version)}func main() {log.Print("Hello world sample started.")http.HandleFunc("/api/hello", handler)port := os.Getenv("PORT")ifport ==""{port ="8080"}log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))}
執行它的第一步是將其構建到Docker容器中。為此,我們從基礎Go Docker映象開始構建以下Dockerfile。
# Use the official Golang image to create a build artifact.# https://hub.docker.com/_/golangFROM golangasbuilder# Copy local code to the container image.WORKDIR /go/src/github.com/haseebh/hello-worldCOPY . .RUN go build -o helloworld-v1 main/helloworld-v1.go# Use a Docker multi-stage build to create a lean production image.# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-buildsFROM alpineCOPY --from=builder /go/src/github.com/haseebh/hello-world-v1 /helloworld-v1ENV PORT8080# Run the web service on container startup.CMD ["/helloworld-v1"]
現在我們只需要構建它。 選擇一個映象tag,然後執行以下兩個Docker命令來構建和儲存映象:
# Build the container on your local machinedocker build -t .# Push the container to docker registrydocker push
在我們部署之前還有一步。雖然我們已經定義了將進入我們的Pod的內容,但我們還沒有定義我們的服務。讓我們做一個簡單的服務定義,稱為Hello Service。我們將它儲存在hello-service.yml服務定義檔案中。
apiVersion: v1kind: Servicemetadata:name: helloworld-v1spec:ports: - port: 80 protocol: TCP targetPort: 8080selector: app: helloworld-v1type: LoadBalancer---apiVersion: apps/v1kind: Deploymentmetadata:name: helloworld-v1labels: app: helloworld-v1spec:replicas: 1selector: matchLabels: app: helloworld-v1template: metadata: labels: app: helloworld-v1 spec: containers: - name: helloworld-kubernetes# replace <image-tag> with your actual imageimage: ports: - containerPort: 8080
現在我們已經擁有了所需的一切。我們的映象已經構建,我們已經根據它定義了一項服務。現在我們終於可以使用Kubernetes來部署它了。我們將使用kubectl命令列工具將其部署在我們的叢集上:
kubectlapply-fhelloworld-go-v1.yaml
要獲取服務負載均衡器IP,請執行以下命令:
kubectl get svc helloworld-v1 -o wide
記下外部IP。
現在,當我們訪問負載均衡器地址時,我們可以看到已部署的服務。它並不多,但“Hello World”向我們展示了這一切都奏效了!
關鍵元件
構建此服務使我們能夠演示大多數主要的Kubernetes元件。首先,我們佈置了Dockerfile來為服務建立程式碼。要在Kubernetes中實際建立服務,我們需要使用YAML來定義它。我們的定義採用我們定義的映象並提供一些關鍵資訊:應該部署的位置,版本以及其他配置資訊。
之後,我們在Pod上部署了該服務。在Kubernetes模型中,Pod與容器密切相關。許多部署(如我們的部署)使用單個Pod進行服務。嚴格來說,Kubernetes不管理容器,它管理。有時這些容器與Pod有一對一的關係,有時候有多個容器關聯到一個Pod。
最後,我們看到了編排的原則。在定義了我們希望如何部署API之後,我們只是將配置檔案推送到Kubernetes並完成其餘工作。使用kubectl,我們能夠指定我們想要的架構,Kubernetes負責其餘的工作。當我們稍後檢視更復雜的示例時,通過多個版本和複雜的部署,我們將更清楚地看到這個簡單想法的強大功能。
深入瞭解
部署簡單的服務只是一個開始。Kubernetes原生支援微服務,它能用很好的方式來部署基本的,甚至更復雜的微服務架構,而不會有太多的麻煩。但要真正利用微服務的可擴充套件性,你還需要知道更多。
在下一篇文章中,我們將介紹Istio。通過微服務方法,我們能夠將單一的應用程式分