Docker容器及Spring Boot微服務應用
1 什么是Docker
1.1 Docker的出現
- 問題一:項目實施環境復雜問題
傳統項目實施過程中經常會出現“程序在我這跑得好好的,在你那怎么就不行呢?! ”
這是一個典型的應用場景,Docker image中包含了程序需要的所有的運行時依賴,比如java的程序,肯定要在image中包含jdk;比如Python的程序,肯定要在image中包含對應版本的Python解釋器。Docker把整個運行時環境打包放到image中,所以搞定了環境依賴問題!
Docker解決了運行環境和配置問題,方便發布,也就方便做持續集成。
- 問題二:系統多用戶的資源隔離問題
Linux本身就是個多租戶的操作系統,可以多人共用,但是如果某個程序狂吃內存和CPU,占用了太多系統資源,這就會影響其他程序的運行。
所以虛擬機出現了,做了良好的資源隔離,不同用戶之間不會相互影響。但是,虛擬機有缺點:創建速度慢,遷移起來麻煩,因為中間加了一層guest os,有了性能損耗,很牛的物理機也就創建幾十個虛擬機,太浪費了……
相對虛擬機的重量級虛擬化方案, Docker出現了,讓虛擬化變得輕量了起來,創建一個container瞬間完成,秒級!
Docker是更輕量的虛擬化,節省了虛擬機的性能損耗。
1.2 Docker概述
Docker 項目的目標是實現輕量級的操作系統虛擬化解決方案。Docker 的基礎是 Linux 容器(LXC-Linux Container)等技術。
在 LXC 的基礎上 Docker 進行了進一步的封裝,讓用戶不需要去關心容器的管理,使得操作更為簡便。用戶操作 Docker 的容器就像操作一個快速輕量級的虛擬機一樣簡單。
下面的圖片比較了 Docker 和傳統虛擬化方式的不同之處,可見容器是在操作系統層面上實現虛擬化,直接復用本地主機的操作系統,而傳統方式則是在硬件層面實現。
(每個虛擬機都將擁有自己的操作系統以及應用程序必須的運行時環境)
(多個容器公用宿主機操作系統,每個容器擁有獨立的應用程序運行時環境)
1.3 Docker的優勢
Docker 容器的啟動可以在秒級實現,這相比傳統的虛擬機方式要快得多。 其次,Docker 對系統資源的利用率很高,一台主機上可以同時運行數千個 Docker 容器。
容器除了運行其中應用外,基本不消耗額外的系統資源,使得應用的性能很高,同時系統的開銷盡量小。傳統虛擬機方式運行 10 個不同的應用就要起 10 個虛擬機,而Docker 只需要啟動 10 個隔離的應用即可。
具體說來,Docker 在如下幾個方面具有較大的優勢。
- 更快速的交付和部署
對開發和運維(devop)人員來說,最希望的就是一次創建或配置,可以在任意地方正常運行。
開發者可以使用一個標准的鏡像來構建一套開發容器,開發完成之后,運維人員可以直接使用這個容器來部署代碼。 Docker 容器很輕很快!容器的啟動時間是秒級的,大量地節約開發、測試、部署的時間。
- 更高效的虛擬化
Docker 容器的運行不需要額外的 hypervisor(虛擬化管理程序)支持,它是內核級的虛擬化,因此可以實現更高的性能和效率。
- 更輕松的遷移和擴展
Docker 容器幾乎可以在任意的平台上運行,包括物理機、虛擬機、公有雲、私有雲、個人電腦、服務器等。 這種兼容性可以讓用戶把一個應用程序從一個平台直接遷移到另外一個。
特性 |
容器(Docker) |
虛擬機(VM) |
啟動 |
秒級 |
分鍾級 |
硬盤使用 |
MB級 |
GB級 |
性能 |
接近原生 |
弱於 |
系統支持量 |
單機支持上千個容器 |
單機支持幾十個 |
1.4 Docker的局限
Docker並不是全能的,設計之初也不是KVM之類虛擬化手段的替代品,簡單總結幾點:
- Docker是基於Linux 64bit的,無法在windows/unix或32bit的linux環境下使用
- LXC是基於linux kernel的,因此container的guest系統只能是linux base的
- 隔離性比KVM虛擬化方案還是有些欠缺,所有container公用一部分的運行庫
- 網絡管理相對簡單,主要是基於namespace隔離
- cgroup的cpu功能相比KVM的等虛擬化方案相比難以度量
- docker對disk的管理比較有限
- container隨着用戶進程的停止而銷毀,container中的log等用戶數據不便收集
1-2,有windows base應用的是不能使用Docker的
3-5主要是看用戶的需求,到底是需要一個container還是一個VM, 同時也決定了docker作為 IaaS 不太可行
6-7雖然是docker本身不支持的功能,但是可以通過其他手段解決(disk quota, mount --bind)。總之,選用container還是vm, 就是在隔離性和資源復用性上做權衡
1.5 Docker VS VM
- 傳統虛擬化中分為兩個類型
Type-1型是指在服務器的硬件平台上先部署虛擬機管理層(Hypervisor),再在Hypervisor之上生成虛擬機,每個虛擬機再安裝操作系統、運行庫與相關的應用.Type-1虛擬化比較常見的是VMware的vSphere、微軟的Hyper-V、Linux的KVM以及Xen.
Type-2型則在裸機之上先安裝操作系統(比如Linux或Windows),再安裝Hypervisor。Type-2的典型代表是VMware的Workstation以及Oracle的VirtualBOX。
由於Type-1型Hypervisor更接近硬件底層,所以可以降低更多的系統開銷,但就Hypervisor本身來說,仍然要有一層基本的OS“墊底”,這也是其仍然會有系統開銷的原因。
而對於容器技術來說,由於本身就源於操作系統的內核(Linux Kernel),所以也就基本不存在Hypervisor所帶來的開銷
- 容器虛擬化技術
與傳統的服務器虛擬化相比,Docker的一重要特點就是在實現應用間隔離的同時,沒有了對於傳統虛擬化來說是必須的Hypervisor虛擬化管理層,因為從本質上來講Docker的內核與Linux是一體的。Docker的根基——LXC就是一個將Linux運行時、庫以及其他軟件運行支撐環境與相關應用進行封閉的技術。從Linux的內核來看,LXC就相當於系統的一個本地進程,實質上與一個裸機(無虛擬化)應用沒有什么區別,從而無需額外的虛擬化指令以及相應的系統虛擬化開銷。因為在傳統的虛擬化平台中,無論Hypervisor做得再輕薄,虛擬機都要先經過本地的OS再透過Hypervisor調用服務器的物理硬件資源,這與直接以系統進程出現的LXC相比,肯定會造成額外的性能影響。
1.6 Docker生命體系
從Docker的應用封裝架構中,可以看出其最基礎的運行內核與底層鏡像就源於Linux的內核,用戶可以將利用Dockerfile生成好的應用鏡像,上傳至遠端的Docker Registry(比如Docker公司自己運營的雲服務,或是私建的Docker Registry),也可以從Docker Registry里下拉一個別人已經建立好的鏡像直接投入到容器中進行運行,相比之下Docker顯然帶給了LXC更靈活的部署與快速應變的能力
在Docker體系中,最關鍵的就是兩個——Docker Registry(通過Docker Hub進行索引)以及Docker Engine,前者在遠端(或稱雲端)負責收集與分發Docker的應用鏡像(Images),后者則在客戶端負責構建Docker應用容器,這明顯就是一個雲服務的AAS理念,當然用戶也可以在自己的數據中心內部建立私有的Docker Registry,以方便在私有雲內迅速生成自己的Docker集群,以應對靈活的、大規模的應用擴展需求。此時,也相當於在企業數據中心內部形成了一個雲+端的Docker架構。
Docker在英語里的意思為“碼頭工人”,而其Logo就好似一艘酷似鯨魚的大船運送一堆集裝箱前往各地的碼頭。而從其理論上看,Docker就像是一個集裝箱,利用LXC技術來整合不同規模、類型、層級的應用鏡像,先通過集中匯總再有序的分發——每個碼頭就是一台服務器(或VM),大船就是Registry,碼頭的工人就是核心Engine,進行集裝箱的裝配,當然它還需要一系列的外圍的支持(比如最重要的管理)。但從總體的 場景來說,Docker的名字還是非常貼切的。
1.7 Docker 關鍵字解析
Docker Image:
Docker image是一個只讀模板,用於創建Docker容器。Image中可以包含linux操作系統、Apache或者Web應用程序等等,用戶可以下載已經創建好的Docker image,也可以創建Docker image給其他用戶使用。每個image是由很多層組成,Docker通過Union File Systems將這些層綁定在一個image中。每個image都以一個初級image做為基礎,然后通過操作指令在這些初級image上添加新層,操作指令可以是運行的命令、添加文件或目錄或者創建可用操作環境等。這些操作指令都被保存在“Dockerfile”文件中。
Docker Container:
Docker image的運行實例。Docker Containers可以運行、啟動、停止或者被刪除,每個container都是隔離的安全應用平台。
Docker registries:
Docker registries用於保存Docker image,也分公用和私用二種。公用的Docker registry就是Docker Hub,用戶也可以創建私有的Docker registry,為其他用戶提供Docker images下載。
Dockerfiles:
Dockerfile是對Docker Container創建過程的描述腳本。每個Dockerfile詳細說明了開始的基礎鏡像,以及隨后一系列在容器中運行的命令和添加到容器中的文件。Dockerfile也可以說明容器對外的端口,啟動時的工作目錄和缺省執行的命令。
LXC:(Linux Container)
Linux Container容器是一種內核虛擬化技術,可以提供輕量級的虛擬化,以便隔離進程和資源,而且不需要提供指令解釋機制以及全虛擬化的其他復雜性。相當於C++中的NameSpace。容器有效地將由單個操作系統管理的資源划分到孤立的組中,以更好地在孤立的組之間平衡有沖突的資源使用需求。
VM:(Virtual Machines)
指通過軟件模擬的具有完整硬件系統功能的、運行在一個完全隔離環境中的完整計算機系統。
Host OS:
指物理存在的計算機上運行的操作系統。宿主機操作系統。
Guest OS:
指運行在VM上的操作系統。例如在一台安裝了Windows NT的計算機上安裝了Vmware,那么,HOST指的是安裝Windows NT的這台計算機,其Host′s OS為Windows NT。VM上運行的是Linux,那么Linux即為Guest OS。
Hypervisor:
Hypervisor是一種運行在物理服務器和操作系統之間的中間軟件層,可允許多個操作系統和應用共享一套基礎物理硬件,因此也可以看作是虛擬環境中的“元”操作系統,它可以協調訪問服務器上的所有物理設備和虛擬機,也叫虛擬機監視器。當服務器啟動並執行Hypervisor時,它會給每一台虛擬機分配適量的內存、CPU、網絡和磁盤,並加載所有虛擬機的客戶操作系統。
目前市場主要廠商及產品:VMware vSphere、微軟Hyper-V、Citrix XenServer 、IBM PowerVM、Red Hat Enterprise Virtulization、Huawei FusionSphere、開源的KVM、Xen、VirtualBSD等。
Bootfs:(Boot File System)
主要包含 bootloader 和 kernel, bootloader主要是引導加載kernel, 當boot成功后 kernel 被加載到內存中后 bootfs就被卸載了.
Rootfx:(Root File System)
rootfs包含的就是典型 Linux 系統中的 /dev(外設訪問接口信息),/proc(系統設備信息),/bin(系統工具集), /etc(APP配置信息) 等標准目錄和文件。對於不同的linux發行版, bootfs基本是一致的, 但rootfs會有差別, 因此不同的發行版可以公用bootfs。
2 Docker及微服務架構
2.1 微服務概念
微服務架構風格是一種使用一套小服務來開發單個應用的方式途徑,每個服務運行在自己的進程中,通過輕量的通訊機制聯系,經常是基於HTTP資源API,這些服務基於業務能力構建,能夠通過自動化部署方式獨立部署,這些服務自己有一些小型集中化管理,可以是使用不同的編程語言編寫,正如不同的數據存儲技術一樣。
2.2 基於Docker的微服務架構
Docker的細粒度松耦合能夠讓我們用一個Docker容器裝載一個場景功能,也就是按照功能角色分類,每個Docker里面裝一個服務或應用,一個服務器上可以運行多個Docker,或者多個Docker分散到多個服務器上運行。整個項目架構可以按照業務邏輯的規划以細粒度的方式分散在各個Docker容器中,並根據HTTP REST API的方式進行整合聯動。
(Docker為基礎的微服務架構)
本圖由上到下分別由:Nginx負載均衡層,綜合業務服務層,單業務服務層,數據庫層等共同組成Docker為基礎的微服務架構。圖中每個服務節點均裝載入單獨的Docker Container中運行,並對外暴露基於Http協議的Port供外界訪問(數據庫容器仍然是基於JDBC的數據庫連接池方式對其訪問)。
- 負載均衡及反向代理層:可采用Nginx作為負載均衡及反向代理服務器,並且作為靜態資源(HTML,圖像文件,JS/CSS等靜態資源)訪問的服務器。Nginx的反向代理配置功能強大,可以根據用戶訪問路徑或訪問的服務資源進行路由轉發,將用戶的請求映射到其下的綜合業務服務層對應的REST API接口中。
- 綜合業務服務層:綜合業務服務層是根據項目具體業務需求划分的多個單業務服務節點的整合。對訪問者提供一組綜合性業務邏輯REST API接口。其特點是只通過HTTP REST API方式調用其下的單業務服務層接口,而不與數據庫通信。
- 單業務服務層:單業務服務層中每個服務節點都是對業務邏輯相對獨立,功能相對集中一組REST API的封裝。其特點是業務功能相對獨立,與其他兄弟節點的功能耦合度低,並直接訪問其下的數據庫存儲層。
- 數據庫存儲層:以Docker Contain為單位的數據存儲層。
此框架實現重點為,在項目前期通過詳細的功能需求分析並按業務邏輯的耦合度划分成多個服務節點,依靠Docker的獨立且低耦合特性在物理層面上實現項目的細粒度分解。
其優點是:
- 1.可以根據用戶的訪問並發量在每個層次進行水平動態擴充,實現訪問壓力負載均衡。
- 2.對業務邏輯的多層次划分可很大程度上提高項目的復用性。
- 3.一旦將業務抽象成產品后,即可實現“用戶按功能選購”的能力。
- 4.由於Docker的開發環境封裝特性,可以簡化項目部署成本,減少運維人員工作負擔。
- 5.由於服務節點采用HTTP REST API的通訊方式,節點的實現可以采用不同運行時環境不同語言不同架構,比如可采用Spring,Play等多種架構方式。
缺點為,在項目設計前期,需要花費較多的時間進行詳細的業務邏輯划分及系統分析。
接下來,我們將實現該架構圖中的每個Docker節點的關鍵技術。
3 Docker 與 Spring Boot
3.1 Spring Boot 簡介
Spring Boot充分利用了JavaConfig的配置模式以及“約定優於配置”的理念,能夠極大的簡化基於Spring MVC的Web應用和REST服務開發。
Spring 4倡導微服務的架構,微服務架構倡導將功能拆分到離散的服務中,獨立地進行部署,Spring Boot能夠很方便地將應用打包成獨立可運行的JAR包,因此在開發模式上很契合這一理念。
特點:
• 創建獨立Spring應用程序
• 嵌入式Tomcat,Jetty容器,無需部署WAR包
• 簡化Maven及Gradle配置
• 盡可能的自動化配置Spring
• 直接植入產品環境下的實用功能,比如度量指標、健康檢查及擴展配置等
• 無需代碼生成及XML配置
3.2 Spring Boot在Docker中運行
在Eclipse中利用Maven的Spring boot+Docker模板搭建項目框架,實現步驟:
1.下載Eclipse的Maven插件。
2.在Eclipse中選擇SpringBoot-Docker模板。
3.創建SpringBoot-Docker項目
基於該模板創建SpringBoot項目后,目錄結構如上圖,編譯后會生成Dockerfile文件及<項目名>.jar文件。
4.在Docker環境下生成Docker Image鏡像文件
由於已經有了Dockerfile文件及本項目的.jar文件,可以將其拷貝到虛擬機Docker環境中,並運行例如:docker build -t <example-service> . 指令,將Dockerfile描述編譯成鏡像文件,並進入本地Docker registries倉庫中。
5.運行Docker Image文件,形成Container實例,與宿主機建立端口映射。
運行例如:docker run -p 48080:8080 -d <example-service> 指令,啟動該項目的Container實例。
6.在瀏覽器上訪問宿主機的48080端口,通過REST API訪問業務接口。
至此,基於Docker Container的Spring boot項目啟動完畢,並可在瀏覽器中訪問。
4 Docker與Nginx
4.1 Nginx簡介
Nginx ("engine x") 是一個高性能的 HTTP 和 反向代理 服務器,也是一個 IMAP/POP3/SMTP 代理服務器。
在高連接並發的情況下,Nginx能夠支持高達 50,000 個並發連接數的響應。Nginx也可作為負載均衡服務器,Nginx 既可以在內部直接支持 Rails 和 PHP 程序對外進行服務,也可以支持作為 HTTP代理服務器對外進行服務。Nginx采用C進行編寫,不論是系統資源開銷還是CPU使用效率都比 Perlbal 要好很多。
Nginx 是一個安裝非常的簡單,配置文件非常簡潔(還能夠支持perl語法),Bugs非常少的服務器:Nginx 啟動特別容易,並且幾乎可以做到7*24不間斷運行,即使運行數個月也不需要重新啟動。你還能夠不間斷服務的情況下進行軟件版本的升級。
4.2 Nginx在Docker中運行
1.先訪問hub.docker.com下載Nginx的Docker Image
可在虛機中的Docker環境中使用指令例如:docker pull nginx下載鏡像文件。
2.查看該鏡像文件
可使用docker images指令查看下載后的nginx鏡像文件狀態。
3.建立nginx反向代理映射及動靜資源分離映射
4.啟動Nginx服務
可使用如下指令例如:
docker run -d -p 8080:8080 -v /some-path/nginx.conf:/etc/nginx/nginx.conf:ro <nginx-container> 啟動nginx代理服務。
至此,基於Docker的Nginx與Spring Boot反向代理架構搭建完畢。
5 Docker 與PostgreSQL
5.1 PostgreSQL在Docker中運行
1.在Docker hub中下載Postgre Image鏡像文件
可以使用tag指令有針對性下載指定版本的鏡像文件。例如:
docker pull postgres:9.4.4
2.運行Postgres Container實例
例如使用指令:
docker run -p 5432:5432 -e POSTGRES_PASSWORD=654321 -d <example-name>
3.確認Spring Boot項目中的數據庫連接配置是否正確
至此,微服務架構圖中所有層次節點均在Docker容器中部署完畢。
作者自述:
本人從事十六年WINDOWS應用/游戲/設備/WEB開發,目前從事Linux,Docker及CAAS雲平台架構設計及開發。
基於全球開源共享理念,本人會分享更多原創及譯文,讓更多的IT人從中受益,與大家一起進步!
基因Cloud 原創,轉發請注明出處
1738387@qq.com (工作繁忙,有事發郵件,QQ不加,非要事勿擾,多謝!)
2015年6月2日