摘要:本文從單機真機運營的歷史講起,逐步介紹虛擬化、容器化、Docker、Kubernetes、ServiceMesh的發展歷程。並重點介紹了容器化階段以後,各項重點技術的安裝、使用、運維知識。能夠說一文講清楚服務器端運維的熱點技術。javascript
文章的名字起的有點糾結,實際上這是一篇真正從基礎開始講解,並試圖串聯起來現有一些流行技術的入門文章。
目前的企業級運營市場,頗有點早幾年前端工程師所面臨的那樣的窘境。一方面大量使人興奮的新技術新方案層出不窮;另一方面運維人員也每每陷入了選擇困局,艱於決策也疲憊於跟蹤技術的發展。
目前的網絡上已經有不少新技術的介紹文章和培訓資料——絕大多數講的比我要好得多。
由於工做緣由,我有比較多的用戶服務經驗。因此我要說的是,寫這篇文章的緣由,不是由於現有資料不夠好。而是這些資料大多都是從技術自己出發,不斷的說「我能夠提供A、我能夠提供B、還有個人特徵C也不錯」。而忘記了問,用戶想要的是什麼,用戶想解決的問題是什麼。
因此不一樣於一般的技術文章使用技術自己串起來全部的內容,本文試圖經過需求和技術的互動發展來串起來運維技術的發展歷程。
在總體系統中,開發和運維都是很重要的,因此如今DevOps的理念早已深刻人心。但本文並不講解開發部分的內容,這裏只集註在運維架構的演進方面。
即使如此,運維也是很是大的一個話題,因此個人目標再縮小一些,只限定在基礎系統軟件的領域。php
最先的時候,一切程序還都很簡單,一臺電腦已經足夠運行。對比起來看,就好像如今單機版的遊戲。程序的執行不須要有網絡,不須要有服務器,只要保證電腦自己正常,程序就能跑的很好。企業中的運維人員,大多也是會裝電腦系統就夠。所以每每是由開發人員兼任,徹底不用像如今的網管同樣睡一覺起來彷佛就已經落伍了。
由於信息共享的需求,在通常企業中,最早獨立出去的是兩種應用:數據庫服務器和文件服務器。特色是,工做人員的電腦上,安裝軟件的客戶端。而數據和資源、信息文件,保存在文件服務器上。你確定看出來了,這既是共享的需求,也是負載均衡的需求。
即使在今天,仍然有不少應用採用這種模式,好比不少的銀行、火車站售票窗口、還有常見的一些大規模網遊。固然這些系統也沿着不一樣的道路演進着,好比大多銀行仍然喜歡使用大型機系統。這種模式一般稱爲「客戶端-服務器」模式,簡稱C/S模式。
在這個階段中,對於一些大型企業和學校,無盤工做站是很流行的一種部署架構。在工做站上有顯示器、鍵盤、CPU、內存,沒有硬盤。系統的啓動由服務器提供,由客戶端網卡完成虛擬硬盤和系統引導的過程。 這樣的系統並不徹底是爲了節省硬盤的費用,在系統的維護上也方便不少,好比殺毒,也只要在服務器的文件區完成殺毒便可。安裝軟件,在一臺工做站安裝完,在其它工做站上就能夠直接共享使用。
在那個時代,Novell是最風靡的網絡系統。當前風靡的Windows Server和Linux在服務器端尚且式微。html
在客戶端安裝一個程序而且保證程序的長期正常運行是挺費勁一個事情。特別是隨着Windows系統快速的升級,和客戶端可能安裝的軟件數量增長帶來的運行環境複雜性增長,兼容性問題成爲另一個麻煩。
因此從用戶、開發人員到運維人員,都開始將程序從客戶端(Client)的方式,轉移到了瀏覽器(Browser)的方式。
這其實就是咱們使用電腦瀏覽互聯網的方式,習慣了手機上網的咱們,可能已經忘記了一個域名就賣出天價的時代。
瀏覽器「開箱即用」的特性很快就風靡業界。Google公司甚至專門爲此研發了只支持瀏覽器環境的Chromebook上網筆記本。在深圳的華強北,大量的輕薄短小的迷你上網本也快速出貨。
由於B/S模式的開發需求快速增長,服務器有了內置WEB服務的要求。因此大量的Linux服務器和WindowsNT/200x服務器開始佔領市場。
在開發語言上,也在短時間內出現了一批適應互聯網編程的開發語言或技術,好比LAMP(XAMP)/C#.net+IIS/Java+Tomcat。前端
不少人認爲現代的虛擬化技術起源於早期大型機時代的分時系統或者硬件虛擬化技術。其實嚴格講並不是如此,上面兩項技術只是提供了一個重要的思路,好比資源共享、好比API向上層穩定兼容。從技術的演進上而言,現代所流行的虛擬化技術跟這些技術都沒有關係。
如今咱們使用的虛擬化技術,主要功能是在一臺電腦中模擬出來完整的另一臺或者幾臺電腦。從而支持另外的、完整的操做系統在其中運行。這另外執行的操做系統,看起來就像是電腦上運行的客戶端程序同樣的效果。但在其中運行的程序,表現跟運行在獨立主機上的程序並沒有不一樣。
在CPU廠商還沒有給CPU內置虛擬化(好比VT)技術以前,這種模擬器就已經出現了。我所考證最先使用這種方式工做的軟件是一款分析、破解應用軟件的軟件。是一個重要的黑客工具,所以軟件的名字在這裏不提。這款軟件完整的模擬操做系統的執行,在其中運行的應用軟件徹底意識不到本身是在一個虛擬的環境中執行。在這種狀態下,軟件的一切動做均可以被跟蹤、記錄而無所遁形,甚至隨時被中斷運行切換到代碼分析模式,從而快速的被破解。
這種工做方式完整的模擬一切,能夠達成工做,可是由於使用了大量的CPU調試中斷,軟件模擬和監控,致使運行效率很是低。因此在生產環境中並不流行,一般主要用戶是開發部門。時至今日,仍然有一些應用採用這種方式工做,好比Android的模擬器,就是基於QEMU的虛擬化技術。不只能夠模擬x86系列CPU,還能夠模擬ARM/MIPS等。
直到從CPU硬件層級實現了對虛擬化的支持以後,配合上軟件的進步,在虛擬計算機中的程序的運行效率才獲得了大幅度提升。在不須要大量顯示資源的後端應用中,運行速度已經無限接近實體真機運行一樣應用的速度。而這偏偏是服務器端軟件所須要的,至此,虛擬化的推廣掃清了障礙。
虛擬化的出現大幅提升了運維效率,也大幅的提升了硬件服務器的利用率,帶來了運維的革命性變化。其實就是從這個時期開始,運維部門才逐漸同研發部門互相比肩,脫離了長期從屬的尷尬地位。
在這一時代,VMWare幾乎一家獨大。服務器端採用 VMware ESXi, 客戶端使用VMware Workstation。盜版的數量恐怕更是正版採購量的十倍以上。
即使在微服務如此普及的今天,不少企業的基礎硬件環境也會首先部署VMware ESXi,再由其中劃分所需資源供微服務架構來使用。
儘管如此,在開源軟件領域,KVM、OpenStack以及其它相似衍生類應用仍然佔領着不大不小可是穩定發展的一塊陣地。
緣由很簡單,虛擬化實際是前幾年火熱的概念「雲服務」的基本基石。爲了提供計算資源給客戶,雲服務廠商基本都須要定製功能、界面給用戶完成大量的自主操做。
這些需求,顯然是VMWare這樣的商業軟件難以實現的。所以在開源系統的基礎上進行延伸開發就成爲了雲服務廠商的必由之路。
所以儘管感受上身邊的同事、朋友都在使用VMWare系列產品,但畢竟不少企業已經選擇租用雲服務器而不建設本身的機房。可想而知,這樣的用戶數量仍是很驚人的。
值得一提的是,原來C/S時代的無盤工做站也與時俱進,以「瘦客戶機」的身份在不少企業普遍應用。這時候的瘦客戶機,並不必定沒有硬盤,重點瘦客戶端啓動以後就會執行「遠程桌面客戶端」程序,鏈接到服務器上虛擬化的桌面系統。從而在表現上如同一個真正的桌面電腦同樣完成正式的工做。
運維人員在這種方式下能夠節省大量客戶端維護的精力。好比某個終端操做系統崩潰,能夠簡單備份一下數據(數據在服務器上的,甚至無需備份),刪除這個客戶端,另外從標準模板執行一個實例出來就完成了新系統的部署。這個過程徹底不須要離開座位,點擊幾下鼠標,操做就完成了。java
本來須要對大量實體服務器進行管理,網管跑機房跑斷腿。有了虛擬化以後,運維人員只要坐在電腦前點點鼠標就能夠完成工做。配合上遠程管理卡(當前的品牌服務器基本已經內置),運維人員已經不多須要進機房了。並且響應速度,比跑機房直接操做實體機快了不知多少。這是上面所說,虛擬化對於運維效率的提高。
更主要的做用,是虛擬化對於服務器資源複用的幫助,這纔是用「革命性」一詞來形容虛擬化的主要緣由。
咱們常常見到,不少應用,實際上對CPU/內存等資源的消耗並不大。好比執行WORD編輯文本的時候,CPU佔用率每每不超過20%,內存用的更是不多。
對於某些最終客戶相關的應用,高峯期和低谷期的設備利用率差異巨大。
所以利用虛擬化技術,在實體機上虛擬多臺服務器,分別執行應用,合理調配各應用的高峯和低谷,對於設備利用率的提升做用很是顯著。
這一簡單的理念貫穿着基礎系統軟件運維技術演進的所有歷史,今天流行的微服務,究其根本,也是在顆粒度上對應用進行了更細緻的劃分,從而更精確、高效的利用計算資源。node
虛擬化的市場巨大,雖然VMWare吃到了最大的一口。但業界的競爭歷來沒有中止。
很快容器技術就脫穎而出,成爲業界新寵。成功的緣由是多方面的,但最硬核的一條,是對系統運行效率的提高。
在上一章咱們說過,虛擬化會在一臺電腦上,虛擬出1臺或多臺電腦,運行另外的操做系統。好比執行了2臺Windows,1臺Ubuntu,1臺Centos。隨後在這些操做系統上,再執行具體的應用。
應用在執行的過程當中,大量的硬件調用經過虛擬主機的操做系統,被虛擬化系統好比VMWare所截獲,再轉換到實體主機的硬件層執行。這個過程已經成爲執行效率進一步提高的瓶頸。
而對於大多數應用來講,其規模遠遠小於操做系統自己,每每是爲了執行一個只有幾十M容量的應用,首先要部署一個上G容量的操做系統。系統啓動過程所耗費的時間也是遠超應用自己。這種狀況下,虛擬化對於計算資源的消耗更是變得尤其突出。
容器則是使用了徹底不一樣的思路,在容器中,每一個應用都共享了實體主機的操做系統自己。只是利用內核提供的隔離技術,徹底沒法發現其它應用的存在,一樣實現了「獨佔」的效果。
在容器中執行的應用,全部操做實際上並非被虛擬化的,跟直接在實體機上的執行從效率上說沒有區別。
容器技術的缺點也是明顯的,就是容器沒法支持實體主機上的多種操做系統,容器中的操做系統,跟宿主機上的操做系統必須是一致的。
好比在Ubuntu主機上的容器中,可能出現Centos/Ubuntu,但不可能出現Windows容器。
容器技術發展迅猛,即使系統軟件巨頭微軟也沒法忽略,傳聞微軟在Windows的容器化上投入了巨大的資源,但截至今日,還沒有有說服力的產品出現。
所以實際上咱們提起來容器,在今天說就是Linux容器(LXC)。
Linux容器的雛形是於1979就出現了的chroot,相信不少Unix類用戶都用過。執行chroot以後,用戶的環境會切換到指定目錄的架構環境之中,只有內核跟宿主機共用,一般是用於解決大量的版本庫兼容性上的問題。
chroot如今也有一個很流行的典型應用可能你知道,就是Android手機上的Linux For Android。衆所周知的,Android系統使用的內核就是Linux,而Linux For Andoird實際上就是首先構建一個完整的Linux文件系統,mount到指定的目錄,而後用chroot將系統切換到這個目錄,從而在手機上獲得了完整的Linux功能。
2006年,Google工程師Paul Menage和Rohit Seth提出了用於進程間隔離的Process Container技術,並在Linux內核中實現,就此奠基了當前Linux容器技術的基礎。次年,爲了不用詞上的誤解,改名爲Control Groups,簡稱cgroups。
當今Linux容器系統層出不窮、百團大戰的盛況,基本都是基於這些技術。由於主要技術難題在內核端已經解決,大大的下降了實現門檻,因此當前多種容器技術的比拼,都是在易用性、自動化和持續集成、以及已經容器化的資源數量上作文章。
在這些競品中,Docker是應用最爲普遍的一個,應當算是事實上的工業標準。後續不少流行的容器技術,每每是基於Docker的進一步創新。python
從本小節開始,會介紹一些安裝、使用的具體知識,但本文主要目的仍然是串起來運維的知識體系。因此詳細的內容,建議到本文提供的連接或者參考資料中繼續學習。mysql
Docker官網地址:https://www.docker.com
Docker最初只有一個開源免費的版本,如今Docker已經分爲社區版(CE)和企業版(EE),後者功能更強,可是收費的版本。一般沒有特殊需求的狀況下,使用社區版本已經足夠了。
若是隻是想簡單學習、實驗,或者基於Docker的開發、測試,Docker還提供有一個桌面版。能夠根據本身操做系統不一樣,在這裏選擇下載:https://www.docker.com/products/docker-desktop,下載須要提早在網站註冊用戶。
桌面版在Mac或者Windows的執行,實際上也是使用虛擬化的方法,首先運行一個Linux的虛擬機,而後在虛擬機中使用Docker的容器功能。而且有Mac/Windows的命令行程序配合Docker的操做。緣由前面已經說了,目前來說,容器技術還只能在Linux中使用。
Docker的生產環境,固然就只能選擇Linux系統。一般若是是研發人員主導的項目,較多會選用Ubuntu系統。由於Ubuntu系統默認配置客戶端工具豐富,桌面絢麗多彩,好看又好用。各組件的升級包發佈很是快,可以快速接觸新的技術和解決存在的Bug。不過對於運維來說,快速發佈的補丁包實際上代理了額外的工做量,因此在此建議使用Ubuntu系統做爲生產環境的話,必定要使用長期支持的LTS版本。
若是是運維人員主導的項目,大多仍是會選擇Centos。Centos至關於RedHat的社區免費版本。系統穩定可靠,較少的默認工具也讓系統佔用較少的資源。對於系統各組件來說,Centos更新會比較慢,每次的更新也會經歷認真、全面的測試,適合於生產環境的穩定、安全需求。
除此以外,由於容器主機對主機自己並無多少操做的需求和工具的要求,因此如今還有不少極簡定製版本的Linux用於Docker的容器主機,好比CoreOS,以及各大IT廠商本身定製的版本。在這些系統中,大多都已經預置了Docker系統,基礎Linux環境每每只有幾十M的容量;使用BusyBox替代大量的Linux基礎命令庫;只保留必要的管理工具和Docker啓動所使用的基本依賴庫。從而把寶貴的內存和硬盤留給容器使用。這種方式很相似於VMware ESXi所使用的方式,可見,各技術之間也在互相的學習和互相的啓發。
Ubuntu和Centos雖然沒有默認安裝Docker,但新本版的系統,好比Ubuntu14.0四、Centos7以後,在軟件倉庫中都已經有了Docker的安裝包。簡單幾行命令就能完成Docker的安裝配置。
Centos之下安裝Docker:ios
//更新軟件源的索引 sudo yum update //安裝Docker sudo yum install docker //啓動Docker服務 sudo systemctl start docker
Ubuntu下面安裝Docker:nginx
//更新軟件源 sudo apt update //安裝Docker sudo apt install docker.io
這種狀況下安裝的Docker通常都不是最新的版本,但一般都是夠用的。因此若是沒有特殊的需求,我建議直接這樣安裝、使用就好。
若是但願安裝最新的版本,能夠添加Docker官方源,而後安裝最新的CE版本。這方面請參考官方文檔:https://docs.docker.com/install/overview/。官方文檔中,左側的目錄裏,有針對不一樣操做系統的安裝方法,請自行學習。
對於大多數應用,我很是建議的學習方式是以閱讀官方的文檔爲主。若是由於英語水平問題但願閱讀中文資料,也儘可能同官方文檔對照着看。由於軟件版本更新快速和翻譯中的錯誤問題,僅僅閱讀中文翻譯文檔每每會有一些讓你費解的問題存在。
完整的學習Docker建議參考官方文檔:https://docs.docker.com/get-started/
文檔寫的很是棒,圖文並茂,清晰易懂。下面只對典型的應用場景作一個串講。
首先是基本概念:
Container: 容器,至關於一臺虛機,可能正在執行,也可能執行結束已經退出(關機)。
Image: 映像。這個是新手容易困惑的。由於在VMWare中沒有這個概念,比較接近的,能夠理解爲已經安裝好的操做系統模板,每次啓動一個容器(虛機),實際是複製一份映像,而後在映像上執行。前面已經說過,容器本質上是跟宿主機共享內核,映像則至關於硬盤的文件系統,固然是創建在某目錄下的根文件系統,只是文件自己,並非磁盤的克隆。
Docker: Docker是這套容器系統的產品名稱,也是命令行管理工具的名稱(命令行工具要使用全小寫字符)。全部對Docker系統的操做,均可以經過命令行完成。直接執行docker
,能夠獲得概要幫助文檔。
(本文的代碼塊中,命令前面的#符號是系統root狀態的提示符,不須要用戶輸入)
# docker Usage: docker [OPTIONS] COMMAND A self-sufficient runtime for containers Options: --config string Location of client config files (default "/Users/andrew/.docker") -D, --debug Enable debug mode -H, --host list Daemon socket(s) to connect to -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default "/Users/andrew/.docker/ca.pem") --tlscert string Path to TLS certificate file (default "/Users/andrew/.docker/cert.pem") --tlskey string Path to TLS key file (default "/Users/andrew/.docker/key.pem") --tlsverify Use TLS and verify the remote -v, --version Print version information and quit Management Commands: builder Manage builds checkpoint Manage checkpoints config Manage Docker configs container Manage containers image Manage images manifest Manage Docker image manifests and manifest lists network Manage networks node Manage Swarm nodes plugin Manage plugins secret Manage Docker secrets service Manage services stack Manage Docker stacks swarm Manage Swarm system Manage Docker trust Manage trust on Docker images volume Manage volumes Commands: attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container deploy Deploy a new stack or update an existing stack diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes Run 'docker COMMAND --help' for more information on a command.
須要注意的是,由於容器的特徵,Docker大多數用法都須要在Linux的root權限下執行,因此請提早使用sudo su
進入到root狀態。Windows/Mac的桌面版由於實際使用的是虛機執行,當前本機的Windows/Mac只是一個顯示終端,因此不須要。像上面同樣只顯示幫助文檔,是少數幾個不須要root權限執行的用法之一。
命令行管理工具雖然是全部docker功能的執行起點,但docker自己實際是一個後臺的服務。這個服務能夠運行在任意電腦上。只要docker命令行管理工具配置後可以同後端服務鏈接、通信就能夠完成管理工做。這也是Mac/Windows版本的Docker桌面版本管理工具的運行模式,後端服務運行於虛機中的Linux中,真正在Mac/Windows操做系統執行的是這個命令行管理工具。
執行一個容器,固然是從準備容器的映像文件開始。映像文件或者本身製做(至關於在VMWare在虛機中安裝操做系統),或者使用別人製做完成的。Docker提供了製做工具,咱們後面再講。
獲取別人製做的映像文件一般兩個辦法:一是從映像倉庫直接下載;二是導入他人導出的映像文件包。
好比咱們想運行一個Ubuntu容器,首先在官方的容器倉庫搜索:
# docker search ubuntu NAME DESCRIPTION STARS OFFICIAL AUTOMATED ubuntu Ubuntu is a Debian-based Linux operating sys… 9298 [OK] dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 279 [OK] rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi… 205 [OK] consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session… 158 [OK] ansible/ubuntu14.04-ansible Ubuntu 14.04 LTS with ansible 96 [OK] ubuntu-upstart Upstart is an event-based replacement for th… 96 [OK] neurodebian NeuroDebian provides neuroscience research s… 56 [OK] 1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5 ubuntu-16-nginx-php-phpmyadmin-mysql-5 49 [OK] ubuntu-debootstrap debootstrap --variant=minbase --components=m… 40 [OK] nuagebec/ubuntu Simple always updated Ubuntu docker images w… 23 [OK] tutum/ubuntu Simple Ubuntu docker images with SSH access 19 i386/ubuntu Ubuntu is a Debian-based Linux operating sys… 16 1and1internet/ubuntu-16-apache-php-7.0 ubuntu-16-apache-php-7.0 13 [OK] ppc64le/ubuntu Ubuntu is a Debian-based Linux operating sys… 12 eclipse/ubuntu_jdk8 Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, … 8 [OK] codenvy/ubuntu_jdk8 Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, … 5 [OK] darksheer/ubuntu Base Ubuntu Image -- Updated hourly 5 [OK] pivotaldata/ubuntu A quick freshening-up of the base Ubuntu doc… 2 1and1internet/ubuntu-16-sshd ubuntu-16-sshd 1 [OK] paasmule/bosh-tools-ubuntu Ubuntu based bosh-cli 1 [OK] smartentry/ubuntu ubuntu with smartentry 1 [OK] ossobv/ubuntu Custom ubuntu image from scratch (based on o… 0 1and1internet/ubuntu-16-healthcheck ubuntu-16-healthcheck 0 [OK] pivotaldata/ubuntu-gpdb-dev Ubuntu images for GPDB development 0 1and1internet/ubuntu-16-rspec ubuntu-16-rspec 0 [OK]
Docker默認的倉庫是官方的Docker Hub,包含了大量的官方映像和社區貢獻的映像。出於安全和穩定性方面的緣由,再加上訪問國外網站的速度問題,一般稍有規模的公司都會創建本身的映像倉庫,這方面的內容請參考官方文檔。
上面的命令執行後,能夠搜索到大量的Ubuntu相關映像。若是你已經知道你須要使用哪個,好比相關文檔中已經說明了,能夠直接使用。若是不瞭解,能夠按照這樣的原則來選擇:
假設咱們但願使用第一個官方出牌,推薦度最高的映像,能夠使用下面命令將映像從官方倉庫下載到本地電腦:
# docker pull ubuntu Using default tag: latest latest: Pulling from library/ubuntu 6cf436f81810: Pull complete 987088a85b96: Pull complete b4624b3efe06: Pull complete d42beb8ded59: Pull complete Digest: sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 Status: Downloaded newer image for ubuntu:latest
pull是docker命令的子命令,表示從倉庫中下拉映像,後面的ubuntu是搜索到的映像名稱。
映像的下載時間依賴網絡速度,一般都很是快,主要緣由是容器的映像,遠遠小於VMWare的虛機容量。好比這個Ubuntu的映像,一般是88M左右(因版本變化會有不一樣)。Docker的映像文件是分層增量存儲的,因此在上面的下載過程當中,能看到多個獨立的下載進度。
如今流行的微服務概念,是從研發端架構設計開始就遵循的一系列方法的統稱。「微」這個字在其中有不少含義。但大多資料作概念解釋的時候,都忽略了容器虛擬化自己的「微」。其實稍微多瞭解一點就會知道,若是沒有容器自己的輕量、高效,不少後續的手段根本就用不上。
映像包下載完成後,能夠使用下面命令列表顯示:
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/ubuntu latest 47b19964fb50 4 weeks ago 88.1MB
這表示咱們本地有了一個映像,名稱爲「ubuntu」。
本地的映像文件,能夠使用save子命令保存爲一個tar文件,用於備份或者提供給其餘網絡不方便的用戶使用:
# docker save ubuntu -o ~/Downloads/docker.ubuntu.tar
load子命令能夠將一個docker存儲的tar文件載入到本地的映像倉庫,若是本地倉庫中已經有了同名的映像文件,則倉庫中的映像文件會被覆蓋:
# docker load -i ~/Downloads/docker.ubuntu.tar
這也是剛纔提到的,第二種獲取映像文件的方法。由於國內的網絡狀況,不少國外的映像資源,沒法直接使用pull子命令獲取。每每須要別人幫助,而後load到本地映像倉庫。
有了映像文件,能夠使用下面的命令啓動一個容器,也就是至關於VMWare中的啓動一個虛機:
# docker run -it ubuntu /bin/bash root@519279bc7105:/#
run是docker的另一個子命令,表示執行一個容器映像。-it是命令行參數,表示分配一個終端用互動的方式執行。docker run --help
能夠更詳細的顯示有關run子命令的文檔。接下來的ubuntu就是剛纔下載的映像文件名稱。
最後的「/bin/bash」是容器啓動後,在給定的根文件系統中,執行的程序入口。這個可能會讓VMWare用戶費解,緣由依舊是VMWare中沒有這個概念,VMWare虛機啓動時候固然是如同一臺真正的電腦同樣從頭開始啓動一個操做系統。
而Docker容器咱們剛纔說了,其實是跟宿主機共享內核,而後部署一個完整的根文件系統,這個環境其實是靜態的。只有在這個環境中真正運行起來一個程序,才表明了容器的運行。上例中,/bin/bash這個外殼交互程序,就是做爲了咱們這個容器的執行入口。
這時候若是另外開一個命令行窗口,執行容器列表子命令ps,能夠觀察到ubuntu映像的執行:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abae98b3ba33 ubuntu "/bin/bash" 11 seconds ago Up 10 seconds inspiring_lalande
在ubuntu的執行窗口,你能夠試着作一些操做。若是對Ubuntu足夠熟悉的話,你會發現,這是一個高度精簡的Ubuntu系統,一般稱爲Ubuntu core,提供用戶在其上部署本身的應用。這是微服務系統的一個重要理念--每一個微服務的設計中,盡力只包含最必須的那些文件系統和庫。從而節省空間、提升效率、更提升了安全性和穩定性。我見過幾個印象深入的系統,其中連bash外殼程序都沒有,即使程序中有未測出的漏洞被黑客利用,由於缺少大量基本必須的系統操做工具,配合上只讀的文件系統,黑客什麼也作不了。
在容器內的操做完成後,ctrl+d或者exit能夠退出容器的bash環境,回到宿主機的命令行。
這時候再次查看容器列表,你會發現剛纔的容器已經消失了:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
這是由於,默認狀況下,ps子命令只列出正在運行中的容器。增長-a參數能夠列出全部的容器,包括已經執行結束退出的:
#docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abae98b3ba33 ubuntu "/bin/bash" 8 minutes ago Exited (0) 14 seconds ago inspiring_lalande
這是容器的另一個重要特徵,當指定的程序運行結束後,退出了程序,也就表明了容器的關閉,或者說中止運行。這在VMWare虛機中一樣沒有相同概念,傳統的虛機即使退出了應用程序,除非顯式的關機了,不然操做系統還維持着虛機的繼續運行。
至此咱們完成了一個容器的完整執行流程,對比傳統的虛機系統,你可能首先的感受就是「快」。容器的啓動速度快、退出速度更快。如今微服務系統的大規模集羣、接近實時的動態部署調整規模等特性都得益於於容器的這種特徵。在傳統的虛機環境中,這是不可想象的。
從新啓動一個已經退出的容器使用start子命令:
# docker start abae98b3ba33 abae98b3ba33 #
參數abae98b3ba33是剛纔ps子命令列表中所獲得的容器的ID號,這個ID號伴隨一個容器的生命期都不會改變。在docker命令行中使用ID號的時候,實際上只須要輸入頭幾位、跟其它ID不會混淆就能夠執行。
start子命令執行後,首先返回一個ID號,而後又回到了命令行提示符。這是由於這個鏡像是在系統後臺執行的。
使用ps子命令查看:
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abae98b3ba33 ubuntu "/bin/bash" About an hour ago Up About a minute inspiring_lalande
能夠看到容器已經在後臺執行了。實際上這纔是容器一般的狀態,咱們剛纔使用-it運行bash外殼來執行一個容器,只是爲了讓你看起來更直觀。正常的應用,好比一個web服務器,執行一個命令行外殼出來是沒有意義的。
若是想回到容器的命令行,來觀察應用的運行狀態,這一般是用於調試。能夠使用attach子命令:
# docker attach abae root@abae98b3ba33:/#
注意此次參數使用了容器ID的簡寫形式:abae。
你確定注意到了,從容器的bash使用ctrl-d或者exit退出後,容器再次退出了。緣由是attach子命令其實是附着到容器的執行進程上去了,跟咱們開始使用-it執行bash是徹底相同的。
這顯然不適合出於調試目的進入容器的操做。何況,一個容器啓動的時候,執行的每每也不是bash外殼程序,而是應用的啓動程序。attach到應用的啓動程序,每每也達不到調試的目的。
在這種狀況下,使用exec子命令,另外執行一個shell纔是合理的選擇:
(代碼塊中的//符號是註釋的意思,該行信息並不須要輸入,也不是系統給出的提示信息)
//固然首先仍是要把中止的容器啓動起來,否則exec子命令是沒法執行的 # docker start abae //由於一般/bin目錄都在PATH環境變量中,因此實際上只執行bash就等於執行了/bin/bash # docker exec -it abae bash root@abae98b3ba33:/#
這一次,若是你退出了容器的bash,你會發現,容器還正常的在後臺運行着:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abae98b3ba33 ubuntu "/bin/bash" About an hour ago Up 29 seconds
其它幾個常常會用到的容器執行方式:
//運行一個ngnix容器,並命名爲mynginx //下次對容器的操做,能夠直接使用命名,而不是容器ID,這很是適合寫持續集成的批處理 // -d是生產中常常會用到的在後臺執行容器,不作互動也不分配終端 # docker run --name mynginx -d nginx //將容器的80端口映射到宿主機8080端口 //docker有完整的網絡組件,能夠爲容器分配網絡地址,請查看相關資料 //但根本上,直接使用宿主機IP,在其中開服務端口才是最高效的方式 # docker run -p 8080:80 -d nginx //若是宿主機有多個網址,還能夠指定端口綁定的IP地址 # docker run -p 211.100.132.14:8080:80 -d nginx //除了映射端口,另外映射宿主機的/webdata文件夾到容器的/var/www/html文件夾 //做爲可負載均衡的集羣,文件的持久化及共享,一般都使用宿主機的文件夾映射到容器來完成 # docker run -p 8080:80 -v /webdata:/var/www/html -d nginx //在前面的基礎上,指定容器的重啓策略爲永遠 //這個能夠保證當容器意外退出甚至宿主機重啓後,容器也會被重啓起來 # docker run -p 8080:80 -v /webdata:/var/www/html -d --restart=always nginx
當一個容器肯定再也不須要後,能夠使用rm子命令刪除,注意若是容器中還有運行所產生的數據,這些數據也會刪除,這跟傳統虛機是一致的:
//首先要使用stop中止容器的運行,在執行中的容器是不能被刪除的 # docker stop abae abae //這是docker命令執行後的回顯 //刪除容器及其數據 # docker rm abae abae #
映像文件再也不使用後,一樣也能夠刪除。注意若是有容器正在使用的映像,是不能夠被刪除的,這種狀況須要中止全部使用到該映像的容器,並刪除容器以後,才能夠刪除映像文件:
docker rmi ubuntu
不一樣於傳統虛機從光盤啓動系統開始一個操做系統的安裝,固然咱們也已經知道了那是很浪費資源而並沒有意義的一件事情。
容器沒有操做系統的啓動過程,所以傳統的系統部署手段都是不能使用的。因此一般上,容器映像的創建,都是基於某個已有的系統。一樣的,咱們創建的映像,也可能成爲別人,或者咱們本身,未來創建映像時候的基礎。因此前面所講Docker映像文件,採用分層增量的組織方式,的確是很是合理的。
若是對於裁剪Linux經驗還不足,我很建議你從最經常使用的centos或者ubuntu映像爲基礎開始安裝本身的應用。
創建映像文件規範的方法是使用docker的build子命令,將編寫的Dockerfile創建成映像文件。Dockerfile的內容至關於一組腳本命令。爲了描述原理,咱們先從更底層的笨辦法開始。
由於咱們已經下載了ubuntu的映像,因此咱們以ubuntu爲例來看一個映像的創建過程。
首先是執行一個ubuntu的容器,這個上一小節就見過了:
# docker run -it ubuntu bash root@bded292dfa72:/#
隨後出現了ubuntu容器的提示符,咱們接下來的操做都在容器的bash外殼中執行。
//更新軟件源 apt update apt dist-upgrade -y //安裝nodejs和包管理器,nodejs是npm的依賴項,會自動被安裝 //另外安裝一個vim編輯器,方便編輯測試程序 apt install npm vim //轉換到工做目錄 cd /opt //編輯nodejs的測試程序 vi server.js
測試程序輸入如下內容,輸入完成後使用:x
保存退出:
#!/usr/bin/env node var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World<br>Here is NodeJs in Docker<br>\n'); }).listen(8080, '0.0.0.0'); console.log('Server running at http://127.0.0.1:8080/');
繼續後續操做:
//將nodejs程序設置爲可執行 chmod +x server.js
至此測試映像所需的安裝工做已經完成,能夠exit退出容器的bash,同時容器也會中止執行。
接着能夠使用commit子命令將一個容器的當前狀態,在本地映像倉庫保存爲一個映像:
# docker commit -m "a nodejs helloworld" --author="andrew" bded292dfa72 nodejshello sha256:5b486e5ec498739c8c35c36a1c47bab19ca2622846de12ae626cf8a4fc4376bc #
-m參數以後爲映像文件的提交信息,能夠理解爲映像文件的描述信息;--author是映像的做者信息;接着是容器ID;最後是保存的新映像的名字,注意必須使用小寫字母。
commit子命令的執行須要一點時間,這取決於映像的大小,執行完成後會返回映像的sha256哈希值。
此時查看映像列表,能夠看到多了一個映像,也就是咱們新建的nodejshello:
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nodejshello latest 5b486e5ec498 57 seconds ago 473 MB docker.io/ubuntu latest 94e814e2efa8 7 hours ago 88.9 MB
咱們來執行、測試一下新創建的映像:
# docker run -p 8080:8080 -d --restart=always nodejshello /opt/server.js e64622cde5124e3fcd70e74a3d687e32f347dfc12f13a55b1f593ee2e7fe4553
容器的啓動速度很是快,立刻你就能夠看到返回的一個hash值,也就是容器的ID。
此時查看容器列表,能看到已經執行的容器,顯示的信息中還有端口的映像信息:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e64622cde512 nodejshello "/opt/server.js" 7 seconds ago Up 6 seconds 0.0.0.0:8080->8080/tcp wizardly_aryabhata
使用curl命令來查看一下執行結果:
# curl 127.0.0.1:8080 Hello World<br>Here is NodeJs in Docker<br> #
可見,server.js已經正常執行了。
以上是手工創建Docker映像文件的方法。使用build子命令自動化創建映像文件,建議參考一下官方的文檔:
https://docs.docker.com/engine/reference/builder/
咱們仿照手工創建映像的例子,只展現一個簡單的Dockerfile構建映像的過程。
首先須要作一個準備工做。Dockerfile是一個自動化的執行文件,確定沒法像上面同樣手工編輯程序。因此這個程序咱們須要提早編輯好,方便起見,還要提早放到咱們的內部文件服務器上。好比咱們最終放置的地址是:http://192.168.1.100/share/nodejs/server.js
。
在生產環境中,較多應用是放置在git倉庫中,開發團隊將代碼提交到git倉庫;運維人員在Docker映像構建時從倉庫中拉出來編譯、部署。中間固然還有測試人員的測試過程,這個是由企業的開發流程決定的,此處不談。
請看咱們編寫的Dockerfile:
FROM ubuntu RUN apt update RUN apt dist-upgrade -y RUN apt install -y npm wget WORKDIR /opt RUN wget http://192.168.1.100/share/nodejs/server.js RUN chmod +x server.js EXPOSE 8080 ENTRYPOINT ["/opt/server.js"]
Dockerfile的內容,按照英文字面意思解釋應當均可以理解。其中最後一行ENTRYPOINT,咱們指定了映像文件的執行入口,這樣咱們未來執行這個映像的時候,就能夠不須要顯式的使用run參數給出了。
將Dockerfile保存到一個工做目錄,而後在該目錄中執行創建映像的命令:
# docker build -t test/hello:v1 .
參數-t以後是將要生成的映像名稱,此次咱們使用了一個完整的名稱,test是倉庫名稱(能夠當作本地的分類名稱),斜線以後的hello是映像名稱,冒號以後則是版本號,這些必須都是小寫。其實只使用一個簡寫的名稱hello,只要沒有重名也是能夠的。在一個大系統中,規範的命名習慣固然是必要的。最後的參數「.」以當前目錄的Dockerfile爲模板來生成映像文件。
映像生成的過程視網速不一樣一般須要執行必定時間,這個過程屏幕的輸出能看到,這跟咱們剛纔手工創建映像文件的過程是徹底相同的。
一直到最後幾行,會顯示相似這樣的內容:
... Step 9/9 : ENTRYPOINT /opt/server.js ---> Running in c10d3d6599dd ---> 74afed533165 Removing intermediate container c10d3d6599dd Successfully built 74afed533165
大意是,一共9個步驟都執行完成。映像提交到本地倉庫後,刪除了用於生成映像的臨時容器c10d3d6599dd。生成的容器ID是74afed533165。
查看當前的容器列表:
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE test/hello v1 74afed533165 3 minutes ago 426 MB nodejshello latest 5b486e5ec498 44 minutes ago 473 MB docker.io/ubuntu latest 94e814e2efa8 8 hours ago 88.9 MB
新生成的映像文件已經存在了,執行容器作一個測試:
// 後臺執行容器 # docker run -p 8080:8080 -d test/hello:v1 // 測試服務 # curl http://127.0.0.1:8080 Hello World<br>Here is NodeJs in Docker<br> #
結果說明,咱們製做的映像已經成功執行了。
Dockerfile的編寫簡單易用,可以將部署和發佈流程固化下來,很是方便在devOps和持續集成項目中應用。但也有一些小缺點,一是腳本自己的調試並不算很是方便,一般以前都要手工先仔細驗證才能編寫到Dockerfile;另外仍然跟咱們的網絡環境有關,大量的環境安裝依賴國外的軟件倉庫,常常碰到網絡超時或者臨時性網絡故障致使映像構建失敗的狀況。
一般大一些的公司都會在境外租用服務器,把映像的構建工做在國外完成,隨後再下載到本地使用;或者使用Docker Hub配合github的自動構建功能在雲端完成構建過程。這個超出本文的範圍,請在有需求的時候在網上搜索相關介紹資料。
Docker是一個功能豐富的容器系統,這裏只介紹了最經常使用的部分。應用場景比較複雜的用戶建議儘早閱讀官方文檔,深刻了解Docker的使用。
Docker的命令行方式固然很方便自動化運維,但對普通用戶講並不友好。
此外當Docker宿主機多起來的時候,管理起來顯然很不方便。
還有就是隨着微服務理念的大量應用,Docker基本系統對於批量的啓動容器、負載均衡、健康檢查、服務發現都很是無力。
這些問題在運維的歷史上其實都有對應的解決方案的。好比負載均衡能夠用Nginx代理、HaProxy甚至硬件的負載均衡器。
從一臺主機出發,對全部的宿主機集中管理也能夠採用經常使用的「堡壘機」方式配合大量腳本。
但這些方案看上去都頗有「補丁」的感受,用起來並不方便,更不友好。
因此一時間,大量基於Docker容器的管理系統層出不窮。固然這也有內核解決了主要的關鍵技術問題,使得開發門檻較低的因素。
這些系統集中解決了多宿主機集羣狀況下的統一管理和容器動態編排方面的問題。由於Linux自己就是開源軟件,這些系統大量的採用了開源軟件資源,加上自主開發的部分代碼。因此實際上看起來不少部分都是雷同或者相似的。
從軟件工程的角度來看,VMWare模式是典型的「教堂模式」,容器固然就是「集市」模式。若是說Linux做爲集市模式的表明,其領導地位還存在爭議的話。在虛擬化平臺的生產應用方面,「集市」模式已經顯著領先了。
通過了2年左右的競爭、淘汰,已經有不少平臺人氣不在了,國內我也知道幾家創業公司悄然倒閉。對用戶來說,最惋惜的是付出的學習成本。
當前用戶比較多的系統中,比較有名的是Rancher、Kubernetes、Swarm。
Swarm是Docker官方推出,惋惜推出的比較晚,不少用戶已經有了本身的選擇,不肯意付出遷移的成本。不然原本Swarm是最有機會一統天下的。
Kubernetes今天看起來彷佛已經成爲了業界領袖,佔有最多的用戶羣。畢竟Google這麼多年最大規模的服務器集羣運營經驗不可小視。因此接下來咱們就看看Kubernetes的解決方案。
Kubernetes(如下簡稱k8s)已經開始了文檔的中文化工做,截至本文成稿的時間,大多數基本的文檔都已經有了對應的中文版。而且得益於容器技術的成熟和輔助工具的完善,新版本的安裝、使用也更容易。
官方文檔位於:https://kubernetes.io/zh/docs/ 建議及早閱讀。
本文仍是立足串講最經常使用的使用場景和相關知識。這部分的概念介紹比起Docker來要多了不少。而且沒有采用一般的技術文章使用的分類辦法,不少相鄰概念也並非同一個層次。但原則上,是須要使用者瞭解和操做的會多介紹。雖然可能很重要,但一般用戶平常根本用不到的,就少介紹或者不介紹。
額外再強調一下前面說過的,k8s同其它不少容器管理平臺相似,都大量的採用了社區貢獻的成熟組件。Google自主開發的部分所佔比例並不大。從這個角度上說,學習一種新的容器管理平臺並不會有不少瓶頸,由於極可能大多數功能、用法,你都已經接觸過了,並不陌生。
k8s運行的硬件環境:
Linux類操做系統。2G以上內存;主節點須要至少2個CPU。集羣內的機器必須有徹底的網絡連接。若是使用k8s的輔助工具協助安裝,建議是Debian/Ubuntu或者Redhat/Centos服務器,以便使用APT或者YUM工具。
k8s須要至少一臺主節點(master),用於進行集羣管理。k8s支持高可用模式,這種方式能夠支持多臺服務器共同作master節點。
通過設置,k8s能夠只有一臺服務器,同時作主節點和工做節點,一般是用於學習和測試。但默認設置工做節點是須要其它的服務器。
k8s的組成比較複雜,若是在虛擬化的初期,用戶維護這樣一個系統恐怕須要一個小團隊。如今官方把全部組件都合理打包成了幾個Docker映像文件。部署k8s系統實際就是下載和啓動相應的Docker容器。即使這樣,手工安裝依然有不小的工做量。很幸運官方又推出了專門的集羣管理工具:kubeadm,這個命令行工具進一步簡化了k8s部署的工做。當前若是在已有的Linux服務器上部署一套k8s只要一名工程師不超過10分鐘的操做。
kubeadm幫助集羣管理員簡化集羣的安裝、維護工做。對於k8s容器的用戶,則是使用kubectl。這一樣是一個命令行工具,幫助容器用戶完成幾乎全部容器相關的操做。這樣分別的提供管理工具,也有利於企業在運維層面更精細的權限管控。
還有一個模塊是咱們在集羣搭建的時候會安裝的kubelet,這個應用一般不須要k8s用戶本身直接執行。這至關於一個後臺服務,運行在全部k8s節點上,進行底層的通信和根據通信對所在的節點進行所需操做。
除了這三個組件,還須要手工安裝的是網絡插件。這個網絡不是Linux自己已經包含的網絡支持。這裏指的是容器之間爲了通信而須要的虛擬網絡設備。咱們前面一再提到過,容器技術實際上基於chroot和cgroups。這些技術其實並不包含網絡。早期的Docker自己的確也並不提供網絡支持。你能夠想象本來運行在一臺電腦上的兩個程序,有大把的手段進行數據共享。而如今隔離成了兩臺虛擬電腦上運行的兩個獨立程序,網絡交互就是必須品了。
隨後由於需求一直都在,大量支持容器的網絡功能包出現。這樣多不一樣團隊開發的網絡包組件,完成的都是一樣的功能,各自有本身的粉絲羣體。因此如今k8s容許用戶自行選擇喜歡的網絡插件,以提供容器間的網絡通信。
你能夠理解爲,有了網絡插件,容器虛機中才能有本身獨立的ip地址,才能進行虛擬服務器之間的數據交換。k8s支持的網絡插件列表能夠在這裏找到:https://kubernetes.io/docs/concepts/cluster-administration/addons/
以上是k8s的基本組成。
圖形界面的粉絲們也能夠歡呼了,k8s的Dashboard組件提供了WEB UI功能,容器用戶也能像VMWare用戶同樣靠鼠標完成工做了。我見過好幾個用戶對於k8s的容器自動編排、負載均衡等並非很須要,純粹就爲了使用Dashboard而配置k8s集羣。Dashboard是單獨的一個Pod,沒有Dashboard並不影響k8s集羣的運行,是在集羣安裝完成後單獨部署執行的。
相似於使用Docker的核心就是操做容器。k8s操做的核心單元是Pod。一個Pod是k8s操做的最小單元,包括一個或者多個容器、存儲、網絡、服務。可能有多個容器的緣由是,稍複雜的應用,可能都不是一個容器能夠承載的。強制放在一個容器裏,每每也增大了粒度,下降了資源使用效率。好比一般一個小網站,可能至少有一個WEB服務器,而後還有一個數據庫服務器。這就是兩個容器。若是是在Docker中,你可能須要分別啓動兩次,而在k8s之中,這兩個容器能夠屬於一個Pod,統一進行管理。此外比較重要的一個概念,k8s能夠根據要求,一次啓動Pod的多個實例,至關於對於某個應用投入了更多的計算資源,從而應對高負荷應用。
Service是k8s管理的另一個對象,容器的運行,歸根結底是對外提供服務。網絡服務實際上就是開放某個端口,經過端口對外提供服務。不一樣於Docker中簡單的端口映射。k8s中能夠啓動某Pod的多個實例,這些Pod中的程序,確定對外提供了同一個接口進行服務。Service能夠提供基本的負載均衡功能,把外部鏈接進來的訪問流量調度到不一樣的Pod上,讓集羣的規模化發生做用。而若是在Docker上,則只能自行配置外加的負載均衡方案來達成一樣的功能,麻煩就不說了,Docker及負載均衡方案之間的銜接使得容器列表發生變更的時候極可能發生服務的阻塞。k8s的負載均衡是使用內部的DNS服務(用於動態解析Pod的IP地址,至關於服務發現)和Kube-Proxy(將流量動態分配到不一樣的Pod)共同來完成的。
Volume就是用於映射到容器內工做目錄的存儲目錄或者設備。k8s在Docker的基礎上根據須要更加細分了存儲設備的類型,包括普通的目錄映射、iSCSI之類的硬件存儲設備、甚至商業雲存儲服務。這讓容器技術更具備實用性。
Namespace容許爲Pod添加更細緻的分類管理。這在大的集羣中很是必要,想一想若是沒有Namespace,幾千臺容器在列表中是怎樣恐怖的場景。
前面已經說過生產使用的集羣環境最好使用redhat/centos或者專門定製的Linux環境。不過簡化操做和保持一致性,這裏仍是以Ubuntu18.04LTS爲例來簡單描述一下k8s的安裝過程。
步驟一:基本準備工做
1.首先是設置集羣中每臺設備的IP地址,咱們這裏使用兩臺服務器來作集羣安裝的示範:
master 10.96.200.150 node1 10.96.200.160
IP地址並無特別要求。但一般上,一個實體機集羣的IP地址應當綜合考慮,位於獨立的地址段。大集羣的內部安全問題若是也是重點的話,還應當考慮劃分VLAN作內部的IP地址隔離。
考慮到集羣可能會逐步擴展,因此在master的地址以後建議空出來部分,以便未來集羣增大以後增長master節點的數量。
Ubuntu18.04版本的IP地址設置作了比較大的改變。再也不使用/etc/network/interfaces的配置文件。而轉爲使用/etc/netplan/下的yaml文件。
netplan之下能夠有多個yaml文件,用於更精細的管理多種環境、多網卡的應用場景。一般剛安裝完系統,默認只有一個文件,這個名字可能因具體版本和設置不一樣不同。咱們的設置比較簡單,就直接在這個文件基礎上編輯就好,請參考下面的內容:
//大多的安裝工做須要使用root權限,因此先進入root模式 $ sudo su //顯示配置文件內容 # cat /etc/netplan/01-netcfg.yaml //如下是文件的內容 # This file describes the network interfaces available on your system # For more information, see netplan(5). network: version: 2 renderer: networkd ethernets: ens33: dhcp4: no addresses: [10.96.200.150/24] gateway4: 10.96.200.1 nameservers: addresses: [10.96.200.1]
這種設置方式很簡單,相信你一看就懂。請根據你的網絡狀況,正確設置這個配置文件。
設置完成後,讓配置文件生效:
# netplan apply
2.設置主機名稱。k8s集羣間的內部通信是使用主機名完成的,管理的時候也是如此。因此建議首先設置有意義、易識別的主機名稱,特別注意集羣間不要重名。
在Ubuntu18.04中,主要有兩個文件須要設置,一個是/etc/hostnamew文件,其中只有一個主機名。
此外是/etc/hosts文件中,127.0.1.1以後的第二個名字。
好比我爲集羣主機設置的名稱爲userver-master,請參考下面兩個文件的內容:
# cat /etc/hostname userver-master # cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 userver.lan userver-master # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
3.關閉系統的swap功能。這個功能至關於Windows下的虛擬內存,當內存不足的時候,系統使用交換分區來把內存中不經常使用的部分交換到磁盤上去。
對於一般的系統而言,內存交換很重要,不少大型的軟件嚴重依靠虛擬內存機制。
但對於一個容器服務器系統,硬盤參與的內存交換顯然下降了效率。是否須要作內存、磁盤的交換,應當由容器內的系統決定,而不是由宿主機。
操做上首先關閉當前系統的交換功能:
# swapoff -a
隨後把磁盤交換分區也關閉,防止重啓後依然使用交換系統:
# vi /etc/fstab //將其中交換分區一行使用註釋符屏蔽起來,好比: # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> /dev/mapper/userver--vg-root / ext4 errors=remount-ro 0 1 #/dev/mapper/userver--vg-swap_1 none swap sw 0 0 /dev/fd0 /media/floppy0 auto rw,user,noauto,exec,utf8 0 0
4.安裝Docker和curl工具:
k8s是基於容器的生產級容器編排、管理工具。當前已經支持多款容器產品,不只僅是Docker。但當前從行業中看,使用Docker做爲基本的容器管理工具仍是主流。
# apt-get update // ... 輸出略 # apt-get install -y docker.io curl // ... 輸出略
這裏安裝的是Ubuntu內置源的Docker,上一小結說過,一般這個版本並不高。但版本高並不必定是好事,大多狀況下用戶最多的版本每每擁有最好的穩定性。但願安裝更新版本Docker的能夠參考相關文檔使用Docker的官方源安裝。
步驟二:安裝kubeadm等k8s基本命令行工具:
//安裝k8s軟件倉庫的簽名 # curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
注意從這一步開始,咱們使用了國內的阿里雲鏡像服務器,嘗試過很多鏡像倉庫,阿里雲的鏡像質量仍是最好的。一直以來,國內的k8s嚐鮮者最大的困難,不是學習、使用k8s,而是獲取k8s的軟件映像。誰讓k8s是Google團隊做品呢:(。在此對阿里雲鏡像團隊的幫助表示致敬,建一鏡像,勝造七級浮屠。
//添加k8s阿里雲軟件鏡像倉庫 # cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF //更新倉庫索引,讓阿里雲鏡像倉庫生效 # apt update //安裝3個基本的命令行組件 # apt install -y kubelet kubeadm kubectl //設置這三個組件不自動更新,如前所述,穩定才更重要 # apt-mark hold kubelet kubeadm kubectl
步驟三:
使用kubeadm集羣管理工具自動安裝集羣主機:
//參數表示: //使用阿里鏡像倉庫,安裝版本v1.13.4(成文時最新的版本) //設置pod工做的網段 kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.13.4 --pod-network-cidr=192.168.0.0/16
由於使用了國內的鏡像倉庫,網絡環境沒問題的話,一般幾分鐘就能完成安裝。屏幕上會有比較長的輸出,若是中間安裝中斷,請根據出錯信息排查問題。一直到最後,會出現相似以下的信息:
...略... To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 10.96.200.150:6443 --token zh248e.ivkr6ui3oboxzlji --discovery-token-ca-cert-hash sha256:5e67092d5979a189e0dbb9265a616e62a25d949205d208630933d1cc101dc039
請將上面這部分信息拷貝到記事本留存下來,之後對集羣的配置管理會用到。
若是安裝完成後,須要對主機的設置進行修改,好比修改IP地址、主機名稱等,須要對k8s的多個設置文件進行修改。若是修改內容多的話,可能每每不如你刪除當前集羣,從新進行配置。
這時候能夠使用以下命令:
kubeadm reset
千萬注意,一個正常使用的集羣千萬不要使用這個命令,剛纔說了,這等於刪除當前集羣:)
接着設置用戶的操做環境。不一樣於Docker必須使用root執行,其實這也是一直被不少用戶詬病的。root操做的隱患有不少,操做不當形成的損失是一方面,由於容器的特徵,事實上在宿主機中使用root用戶查看當前進程,全部容器中的程序都是無所遁形,這在安全性上也是沒法接受的。
k8s部署集羣的時候固然必須使用root,但投產後開始運維,容許使用普通用戶操做集羣。
設置方法也很簡單,就是集羣初始化時候最後輸出信息的部分:
//退出root狀態到普通操做用戶 # exit $ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
此時,在這個用戶下,已經能夠作基本的k8s操做了,咱們來看一下當前有哪些Pods運行着。固然,這些都是k8s自己的,咱們本身尚未運行任何Pod。默認狀況下k8s本身的Pods是不會被列出的,因此咱們這裏使用了--all-namespaces參數:
$ kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-78d4cf999f-6pgfr 0/1 Pending 0 87s kube-system coredns-78d4cf999f-m9kgs 0/1 Pending 0 87s kube-system etcd-master 1/1 Running 0 47s kube-system kube-apiserver-master 1/1 Running 0 38s kube-system kube-controller-manager-master 1/1 Running 0 55s kube-system kube-proxy-mkg24 1/1 Running 0 87s kube-system kube-scheduler-master 1/1 Running 0 41s
列表中是組成k8s的全部組件,但願詳細瞭解k8s內部機理的同窗能夠按圖索驥瀏覽詳細的文檔。
注意最上面的兩個CoreDNS尚處於Pending狀態。這是由於咱們尚未配置網絡插件。
步驟四:安裝網絡插件。
前面說過,由於容器技術自己並不包含網絡功能。因此社區中自發的爲容器開發了多種插件,其中可以被k8s支持的,在前面給出的連接中已經有詳細介紹。能夠根據本身的習慣選用。這裏的安裝使用Calico。
功能上,Calico會爲每一個容器分配一個IP地址,這個地址段是咱們前面初始化集羣的時候給定的,也就是:--pod-network-cidr=192.168.0.0/16。
每個k8s節點至關於一個路由器,把不一樣nodes中的容器鏈接起來。
安裝方法以下:
kubectl apply -f http://mirror.faasx.com/k8s/calico/v3.3.2/rbac-kdd.yaml kubectl apply -f http://mirror.faasx.com/k8s/calico/v3.3.2/calico.yaml
由於網絡緣由,咱們一樣適用了國內鏡像,這樣速度會很是快。
注意從一步開始,咱們已經能夠使用普通的操做用戶來操做k8s集羣。而這兩條命令,實際就是執行兩個Pod,這兩個Pod就賦予了容器網絡功能。
這種軟件的分發、配置、使用的方法,跟以往的傳統虛擬化時代有了本質的不一樣。
一個大的軟件,也會分解成多個小的容器來組裝而成,相信你對「微服務」也有了更多感受。
稍等幾十秒,讓Calico運行起來,咱們能夠再查看一下容器的狀態:
$ kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-node-x96gn 2/2 Running 0 47s kube-system coredns-78d4cf999f-6pgfr 1/1 Running 0 54m kube-system coredns-78d4cf999f-m9kgs 1/1 Running 0 54m kube-system etcd-master 1/1 Running 3 53m kube-system kube-apiserver-master 1/1 Running 3 53m kube-system kube-controller-manager-master 1/1 Running 3 53m kube-system kube-proxy-mkg24 1/1 Running 2 54m kube-system kube-scheduler-master 1/1 Running 3 53m
能夠看到,最上面增長了一個calico的Pod,兩個CoreDNS的Pods也執行起來了。
至此一個基本主控節點的k8s已經部署完成。
步驟五:添加工做節點。
工做節點能夠有多個,咱們這裏只演示一個。首先參考前面步驟一和步驟二,如同Master節點同樣,完成前兩步的各項準備工做。
隨後執行以下命令:
//執行拷貝自Master節點初始化的時候輸出信息的最後一行 kubeadm join 10.96.200.150:6443 --token zh248e.ivkr6ui3oboxzlji --discovery-token-ca-cert-hash sha256:5e67092d5979a189e0dbb9265a616e62a25d949205d208630933d1cc101dc039 ...略去的輸出... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the master to see this node join the cluster.
只須要執行這一行命令,就能夠完成把工做節點加入到集羣。命令的輸出信息中,若是顯示上面相同的最後幾行,則表示加入集羣成功了。
上面命令的原型以下:
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
其中token和hash值都是由Master節點生成的,若是最初忘記了備份這些信息,都須要到Master節點上去獲取:
//在Master節點上執行 //獲取token值 $ kubeadm token list zh248e.ivkr6ui3oboxzlji //獲取hash值 $ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //' 5e67092d5979a189e0dbb9265a616e62a25d949205d208630933d1cc101dc039
token是有時間限制的,默認爲24小時。若是超過期限加入工做節點,須要從新生成token:
//在Master節點執行 $ kubeadm token create
如今能夠到主控節點上驗證一下集羣的工做狀況:
$ kubectl get nodes NAME STATUS ROLES AGE VERSION userver-master Ready master 17m v1.13.4 userver-node1 Ready <none> 15m v1.13.4
狀態都是Ready,表示集羣正常工做。注意工做節點加入集羣須要一點時間,這跟服務器的運行速度有關,因此有可能須要稍等片刻工做節點纔會在列表中出現。
步驟六:其它可選配置。
1.默認安裝狀況下,主控節點是不參與容器執行,只進行集羣管理工做的。這在小的集羣中,可能有浪費資源之嫌。這種狀況下,能夠取消Master節點上的「不可靠」標記,從而主控節點也能參與容器的部署運行。
注意「不可靠」標記是k8s的一種機制,用於標記運行中出現故障的節點,避免新的任務分配到故障節點上去。在這裏固然不是指主控節點也故障了,而是不但願主控節點承擔容器的工做,專一於對集羣的管理。
$ kubectl taint nodes --all node-role.kubernetes.io/master- node/userver-master untainted error: taint "node-role.kubernetes.io/master:" not found
上面的執行結果中,第一行是去掉了主控節點的taint標記,第二行是在userver-node1上執行沒有找到這個標記,不用去除,因此這個報錯是正常的,不用理會。
使用這種方式,也能夠在單獨一臺服務器上體驗完整的k8s。Win/Mac版本的桌面版Docker內置了k8s,也是採用了相似的方式在一臺電腦上提供出來完整的k8s實驗環境。
2.安裝Dashboard。
Dashboard是k8s的Web界面的UI系統。這個組件只是爲了下降使用難度,提高用戶友好度。可是從功能上,並非必須的。喜歡使用鼠標操做的用戶能夠本身安裝。
Dashboard是以Pod的形式發佈的,因此所謂安裝,其實就是執行一個Pod,這根前面安裝的網絡插件方式同樣。官方提供了配置文件bernetes-dashboard.yaml能夠直接運行。可是因爲國內網絡的問題和複雜的權限問題,我建議使用修改版。
首先下載阿里雲的鏡像版本的配置文件:
$ curl -O https://raw.githubusercontent.com/AliyunContainerService/k8s-for-docker-desktop/master/kubernetes-dashboard.yaml //下載後編輯文件,作咱們須要的修改 $ vi kubernetes-dashboard.yaml //文件的最後,服務設置部分,替換成下面的內容: # ------------------- Dashboard Service ------------------- # kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kube-system spec: ports: - port: 443 targetPort: 8443 nodePort: 32767 selector: k8s-app: kubernetes-dashboard type: NodePort
修改的內容,是將本來只能本機訪問的端口映射出來到節點主機的32767端口。
網上大多數資料都是使用kubectl的proxy子命令來作Dashboard服務映射。但問題是大多使用Dashboard的用戶都不會知足於只在服務器本機使用瀏覽器,況且服務器版本的Ubuntu根本沒有圖形界面。而把端口映射到外面會有不少安全性問題和權限控制問題。因此除非你對k8s很是熟悉,而且有能力本身定製一些安全機制,不然不建議那樣使用。
配置文件修改好了以後,使用以下命令執行:
$ kubectl apply -f kubernetes-dashboard.yaml
若是是第一次運行的話,須要下載映像,阿里雲的鏡像網站仍是速度挺快的,應當不用等好久。
繼續使用kubectl get pods --all-namespaces
命令能夠查看Pod的執行狀況,從而瞭解Dashboard是否正常運行。
順便提一句,apply執行Pod只須要運行一次。由於複製器的功能,之後重啓系統後,Dashboard也會自動啓動起來。這個在概念部分說過了。
接下來還要爲Dashboard創建一個管理員用戶,系統內置的default用戶權限過小,大多信息都沒法查詢,因此不建議使用default。
請將下面內容保存到一個配置文件,好比叫dashboard-adminuser.yaml:
apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kube-system
而後在集羣執行:
$ kubectl apply -f dashboard-adminuser.yaml //用戶創建後,獲取admin用戶的Token $ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') //將下面輸出的token部分拷貝備份起來,做爲未來的登陸使用 Name: admin-user-token-snppt Namespace: kube-system Labels: <none> Annotations: kubernetes.io/service-account.name: admin-user kubernetes.io/service-account.uid: 6ec3f9a0-4796-11e9-ade6-000c29dfacdd Type: kubernetes.io/service-account-token Data ==== ca.crt: 1025 bytes namespace: 11 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXNucHB0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2ZWMzZjlhMC00Nzk2LTExZTktYWRlNi0wMDBjMjlkZmFjZGQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.eFIzEuGyY_ipi2bLH7tYbDnkjFmDK_sT1uvAmV7dU2mpxgTptpo7tI2qSNmijRcf5LG02ft5rqq5F_IM3jFHrhhwnMG6wz9ccpABR1oqQE8FYxFo8sflETbeUMFCtbm7uPUMI-H4civ6lA_8hZtNKy4VHUUOlAWGDu1EPUV7RBgmX2a2cbcQLlaUWVS_xAG8A5jSHD_LgWM4GEqN5kq2tNCiVNJkf1FHNx9m9x_BJM4ZJCdhKJdVIjnxORG7gUGQeLXr0Q8iRRi0bFqSoAn213Ml2WQbX2RsB0W1ty144EzSj8KeX6uwhN2n2TGsqXJN5S76AArSl4rxKBk9bInkDg
如今使用https協議訪問主控節點IP地址的32767端口就能看到控制檯登陸界面了:https://10.96.200.150:32767,由於使用了私有的證書,因此還要確認忽略掉瀏覽器的警告信息窗口。
登陸Dashboard控制檯使用Token模式,這個Token就是咱們剛纔創建用戶的時候所得到的TOKEN,跟前面加入工做節點所使用token的不是同一個東西。
Dashboard還能夠安裝一些酷炫的插件,用於圖形化的顯示系統的負載、使用狀況,有興趣能夠參考此文:https://iamchuka.com/install-kubernetes-dashboard-part-iii/
至此,集羣的安裝所有結束。
先從執行一個容器開始,固然這個容器在k8s中是以Pod的形式執行的。下面這條命令,將創建並下載、運行一個nginx容器:
$ kubectl create deployment nginx --image=nginx:alpine deployment.apps/nginx created
執行完成後,查看執行的Pods列表:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-54458cd494-5g5cq 0/1 ContainerCreating 0 14s
這表示nginx部署已經開始創建,實際上由於第一次運行nginx,這個過程主要是從網上下載映像文件的時間。一般速度都很快,若是你進入root用Docker查看一下nginx映像,你會發現容量只有使人驚訝的16M。
固然,由於咱們身處國內,這麼小的映像,也有可能沒法下載。碰到這種狀況你只能本身想一想辦法了:)
稍等再次執行查看Pods列表:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-54458cd494-5g5cq 1/1 Running 0 56s
這說明nginx容器已經部署而且執行,而且k8s內置的複製器組件會保證集羣中始終有一個nginx容器在執行。相似出現運行中的nginx容器死機了或者崩潰了,k8s的複製器會刪除當前容器並從新執行一個nginx容器從而保證容器數量爲1。
好比咱們嘗試直接刪除這個Pod:
$ kubectl delete pods nginx-54458cd494-5g5cq pod "nginx-54458cd494-5g5cq" deleted
再次查看Pods列表:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-54458cd494-4v4v8 1/1 Running 0 6s
能夠看到,nginx-54458cd494-5g5cq已經不見了,取而代之的是:nginx-54458cd494-4v4v8。
咱們一下子再學習如何正確刪除Pods,先繼續複製器的話題。
複製器是一個強大的工具,基本透明的貫穿在k8s之中,大多數不須要單獨的操做。Google官方自稱k8s爲「生產級別的容器編排系統」,這個編排實際就是複製器的基本能力。而由於有了這種自動編排,以併發換速度;以快速啓動新的容器替代有故障的容器,纔是「生產級」的內涵。
下面咱們能夠操做複製器,把當前執行的nginx容器擴展爲3個:
$ kubectl scale deployment nginx --replicas=3 deployment.extensions/nginx scaled $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-54458cd494-4v4v8 1/1 Running 0 10s nginx-54458cd494-5g5cq 1/1 Running 0 4m15s nginx-54458cd494-mxmqq 1/1 Running 0 10s
列表中,原有的容器還在,另外增長了2個,共3個Pods在運行中。
這裏強調一下,k8s爲大規模的併發提供了運維手段。但軟件的研發須要相應的從設計伊始就將併發的支持貫穿在開發中。好比多臺服務器間如何同步數據、共享session等。不然同時併發大量的服務器不只不能提升系統的負載能力,反而可能形成數據的混亂或者系統的互鎖。
kubectl的get子命令是獲取k8s各項信息很經常使用的工具,須要認真掌握。好比咱們讓列表顯示更多信息:
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-54458cd494-4v4v8 1/1 Running 0 76s 192.168.1.5 userver-node1 <none> <none> nginx-54458cd494-5g5cq 1/1 Running 0 5m21s 192.168.1.4 userver-node1 <none> <none> nginx-54458cd494-mxmqq 1/1 Running 0 76s 192.168.0.10 userver-master <none> <none>
在生產環境中,當運行的Pods比較多的時候,咱們還須要對列表進行過濾。否則你根本找不到你須要的Pod。好比使用app的名稱進行過濾:
//使用了過濾器,固然這裏跟上面執行結果是同樣的,由於咱們沒有運行別的Pods $ kubectl get pods -o wide -l app=nginx NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-54458cd494-4v4v8 1/1 Running 0 76s 192.168.1.5 userver-node1 <none> <none> nginx-54458cd494-5g5cq 1/1 Running 0 5m21s 192.168.1.4 userver-node1 <none> <none> nginx-54458cd494-mxmqq 1/1 Running 0 76s 192.168.0.10 userver-master <none> <none>
k8s經過etcd組件支持使用key/value對兒的標籤體系和標籤過濾來精肯定位Pods,從而下降操做複雜性。好比刪除Pods的時候,也能夠使用這種標籤過濾的方式選擇多個刪除對象,:
$ kubectl delete pods -l app=nginx pod "nginx-54458cd494-4v4v8" deleted pod "nginx-54458cd494-5g5cq" deleted pod "nginx-54458cd494-mxmqq" deleted
固然了,由於複製器的存在,當前的三個容器被刪除,複製器會自動啓動3個新的容器,來保證nginx容器總數爲3:
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-54458cd494-cjcjr 1/1 Running 0 20s 192.168.0.11 userver-master <none> <none> nginx-54458cd494-ncz4n 1/1 Running 0 20s 192.168.1.7 userver-node1 <none> <none> nginx-54458cd494-vjzb6 1/1 Running 0 20s 192.168.1.6 userver-node1 <none> <none>
能夠分別測試三個Pods的工做狀況:
$ curl 192.168.0.11:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> $ curl 192.168.1.7:80 ... //80端口是默認的http端口,能夠省略 $ curl 192.168.1.6 ...
如今三個容器都正常工做了,但訪問都是經過的內網,若是想在外網訪問,就須要配置k8s的端口服務,把端口暴露出來:
$ kubectl expose deployment nginx --port=80 --type=NodePort service/nginx exposed
service的概念咱們前面講過,這裏實際上就是創建了一個服務,類型是NodePort。把容器的80端口開放出來,到一個隨機的端口號,端口號的範圍默認是30000-32767能夠修改。端口的映射是由kube-proxy完成的,由於kube-proxy在每臺節點服務器上都會運行,因此訪問任一節點的IP地址,配合這個指定的端口號,就能夠訪問到nginx的輸出,這種模式就叫NodePort。kube-proxy的映射功能同時包含了負載均衡的流量分配能力。而且由於服務的創建就是映射到了指定的Pods羣,也無需再次進行服務發現。
使用下面命令查看這個服務的具體信息,其中有端口號:
$ kubectl get services nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.106.91.63 <none> 80:31739/TCP 2m29s
上面信息代表,對外映射的端口爲31739。其中CLUSTER-IP是在容器內部訪問時候使用的,在外部是訪問不到的。這裏的CLUSTER也不是指的k8s集羣,而是指是咱們啓動了幾個nginx Pods,是運行在k8s集羣上的nginx的集羣,這一點必定不要誤會。之因此單獨給出一個獨立的內部IP地址,是由於在開發中,內部的服務訪問一樣也須要負載均衡和隱含其中的服務發現。
咱們測試一下:
$ curl 10.96.200.150:31739 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> $ curl 10.96.200.160:31739 ...
在實際應用中,訪問任意一臺節點的對應端口都是能夠的。端口服務創建的時候,也能夠指定只捆綁某個IP地址的端口,請參考命令的幫助文檔。
下面咱們再開一個Pod,看看容器內部對其它容器的訪問。
此次咱們開一個busybox的容器,以便使用bash shell操做:
$ kubectl run -it --generator=run-pod/v1 curl --image=radial/busyboxplus:curl [ root@curl-66959f6557-wpp5p:/ ]$
由於咱們但願使用互動終端的方式(參數-it)執行Pod,因此直接使用kubectl的run子命令。
執行以後,若是是第一次使用busybox,須要下載映像,因此要有片刻的等待。固然速度也會很快,由於這個映像只有4M多的容量。
隨後出現的提示符,已是容器中的shell提示符。
在其中執行:
[ root@curl-66959f6557-wpp5p:/ ]$ nslookup nginx.default.svc.cluster.local Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: nginx.default.svc.cluster.local Address 1: 10.106.91.63 nginx.default.svc.cluster.local [ root@curl-66959f6557-wpp5p:/ ]$ curl nginx.default.svc.cluster.local <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
注意名稱:nginx.default.svc.cluster.local是咱們剛纔創建的端口服務的全稱。也就是nginx這個名字,加上.default.svc.cluster.local後綴。獲得的IP地址,你會發現,跟上面的CLUSTER-IP地址是徹底相同的。
由於不管是CLUSTER-IP,仍是每臺容器的地址,都是動態變化的。因此在編程中,應當堅持使用nginx.default.svc.cluster.local這樣的名稱來訪問其它的服務,就像上例中curl獲取nginx首頁作的那樣。這樣作一是保證程序的可遷移性,也是爲了利用系統內置的負載均衡機制。
Pod一旦創建,無論是Pod崩潰退出,仍是集羣重啓,都會自動從新運行。而且會保證數量跟複製器設定的數量吻合。
因此當容器再也不須要的時候,咱們須要顯式的刪除,方法以下:
//刪除對外的端口服務 $ kubectl delete services nginx service "nginx" deleted //刪除部署 $ kubectl delete deployment nginx deployment.extensions "nginx" deleted $ kubectl delete deployment curl deployment.extensions "curl" deleted //一些容器的中止須要時間,因此稍等再執行... $ kubectl get pods No resources found.
上面介紹的,是從使用VMWare起步,到Docker,再延伸而來的習慣,是基於映像文件的使用方法。k8s的魅力遠非止步於此。
咱們使用中可能有不少感覺,就是用這種方式使用容器,命令行冗長,不容易記憶,更不方便修改和定製,對於寫入腳本重複使用也不方便。
k8s引入了使用參數文件來表述容器的各方面配置,易讀易用。官方推薦的是yaml文件。
在上一小節介紹安裝的時候說過,Ubuntu新版本中也把yaml格式做爲部分配置文件的標準。yaml算得上繼json以後最新一代的結構化文檔格式了。yaml文件有幾個簡單的須知:
- 大小寫敏感
- 使用縮進表示層級關係
- 縮進時不容許使用Tab鍵,只容許使用空格。
- 縮進的空格數目不重要,只要相同層級的元素左側對齊便可
表示註釋,從這個字符一直到行尾,都會被解析器忽略。
k8s也支持json格式的配置文件,只是網上大多數存在的資源都已經使用了yaml,因此建議你也從yaml開始,跟社區保持相同。
在官方的文檔中,編寫配置文件的說明並非yaml使用說明,而是「使用Deployment運行應用」,路徑爲:https://kubernetes.io/zh/docs/tasks/run-application/run-stateless-application-deployment/,必定要仔細閱讀。
做爲串講,這裏舉一個小例子。首先列出yaml文件:
--- apiVersion: v1 kind: Pod metadata: name: web-site labels: app: web spec: containers: - name: nginx image: nginx ports: - containerPort: 80 - name: helloecho image: hashicorp/http-echo args: - "-text=hello" ports: - containerPort: 5678 --- apiVersion: v1 kind: Service metadata: name: web-site-svc spec: type: NodePort ports: - name: nginx-port port: 80 targetPort: 80 - name: helloecho-port port: 88 targetPort: 5678 selector: app: web
使用「---」分割線隔開,這個文件中包含了兩個k8s任務,一個是定義Pod,一個是定義對外暴露端口的服務。每一個yaml文件中,包含一個任務就能夠。但爲了便於管理,完成一個工做的多個任務習慣寫在一塊兒,這樣一次執行就能完成所有工做,而且不用擔憂執行的順序。
apiVersion一行指的是k8s的接口版本。yaml實際至關於根據k8s的接口規範來完成任務。
kind指定任務類型,這裏分別演示了Pod和Service。
metadata部分是任務相關的key/value對兒,name是必須的,最終就是Pod和Service的名字。labels下面的則是本身定義的,本身定義的目的是爲了未來對相關對象的檢索。好比Service定義暴露端口的時候,使用selector指令使用app檢索爲:web的Pod。
這是一個典型的一個Pod中包含多個容器的示例。下面的spec中是定義的主要部分,我以爲不用多解釋應當能看懂。這裏使用了一個標準的nginx,一個http協議的echo小工具。echo工具的定義裏面,使用args指令指定參數「-text=hello」來定製一個「hello」的字符串反饋信息。不少簡單系統裏面,會用這個小工具作健康檢查的信息反饋。
服務的定義裏面,使用NodePort模式(看咱們前面的例子)來暴露兩個對外服務端口,分別映射到nginx和echo兩個容器。
上面的文件保存到一個yaml文本文件,好比叫:web-test.yaml。隨後能夠執行這個文件:
//執行配置文件,創建Pod和Service $ kubectl apply -f web-test.yaml pod/web-site created service/web-site-svc created //查看Pod $ kubectl get pods NAME READY STATUS RESTARTS AGE web-site 2/2 Running 0 14s //查看服務 $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31d web-site-svc NodePort 10.104.214.83 <none> 80:31686/TCP,88:30298/TCP 7s //測試nginx $ curl 127.0.0.1:31686 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> //測試echo $ curl 127.0.0.1:30298 hello
若是有root權限,還能夠進一步使用docker ps來檢查一下容器運行的狀況。能夠看到同一個Pod中的nginx跟helloecho分別是兩個不一樣的容器。這裏就略掉了。
若是Pod沒有像預期的同樣執行,使用kubectl get pods命令查看pods列表的時候會看到狀態不是Runing。若是仍然沒法判斷錯誤來源,使用命令kubectl describe pods web-site可以看到同Pod相關的全部詳細信息,其中包括出錯的信息,能夠幫助你判斷未能啓動的緣由。
測試過程結束後,依靠配置文件刪除這個應用也變得簡單了:
$ kubectl delete -f web-test.yaml pod "web-site" deleted service "web-site-svc" deleted
你可能還有一個疑問,這兩個容器之間,彷佛什麼關係也沒有啊,爲何要放到一個Pod中?的確如此,一方面這裏僅僅是個演示,簡單介紹如何使用yaml配置文件自動化部署的過程。再者,從運維端看,運維的目的就是把各部分容器正常運行起來,時刻讓其保持在健康的狀態,及時處理各種異常事件。
從某一個容器中,如何訪問另一個容器的計算結果,並進行有機的組合和相關處理,是軟件開發過程當中解決的問題,運維人員基本沒有可能去幹涉。
在k8s集羣的運維過程當中,Docker容器層產生的過時容器及再也不使用的鏡像,會由Image Collection
及Container Collection自動回收,正常使用狀況下,並不須要運維人員手工刪除。
做爲全面操控k8s的配置文件,這算的上最簡單的例子。還有不少指令須要學習,請儘快閱讀相關文檔。參考別人的使用示例也是快速學習的一種手段,推薦一個使用k8s配置WordPress應用的講解:https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
通常來講,構建k8s集羣中的生產環境,同之前使用傳統虛機的方式並無什麼不一樣,一般是這樣的工做流程:
k8s在企業級運維的佔用率快速的增加,然而新的需求繼續出現。
最核心的問題是,k8s的集羣系統,是由主控和工做節點兩個部分作成的。小的集羣中,只須要一個主控節點。大集羣中,k8s提供了高可用的模式(Highly Available Clusters),這種模式支持最少3臺主控節點組成主控組,來統一管理整個的k8s集羣。
可是即使在這種高可用的模式下,仍然須要配置負載均衡機制,好比HAProxy,放置在控制羣組以前,這無可避免的成爲了又一個單點瓶頸。
此外還有一些需求,好比對容器的監控功能不足,調試容器的配置問題須要研發團隊配合輸出大量的日誌信息。再好比紅黑髮布的導流控制等。
在開源社區中,只要有需求,就有大量的團隊爲此努力,開發出一樣大量的產品或者插件。在其中,此次是Istio脫穎而出。
簡單來講,Istio採用了比較新的思路來解決問題。最主要的就是,本來每一個容器,須要同管理節點之間創建通信鏈接,溝通容器狀態及接受控制信息。由於這種機制,管理節點的健康情況和負載能力,成爲了整個系統的瓶頸。
Istio一樣也是在容器上配置本身的組件(Sidecar),但這些控制數據流,再也不溝通到某個具體的管理節點,而是全部節點直接互相溝通,組成了一個服務網格(ServiceMesh)。網格中任意一個容器出現問題,並不影響整個網格的信息傳遞和控制,故障的容器一樣也會在服務支持下被刪除,並被新生成的容器替代。系統再也不存在單點瓶頸。
Sidecar的核心是代理機制,接管了全部進出容器的通信流。在這種機制的幫助下,在流量管理、安全性、控制、和監控方面,顯然有了更可靠的手段。所以在Istio首頁(https://istio.io)上,這四個特徵成爲了主要的賣點:
應當說單純這些功能,在社區中都有不錯的組件能夠完成,爲了少許的需求安裝一個輕型的組件也很經濟。實際上Istio也直接或者間接的使用了大量社區貢獻的組件。但有一點必定要明白,雖然安裝一樣的組件可以完成一樣的功能,但除非使用了Istio的Sidecar機制,不然需求是知足了,但並無解決單點瓶頸問題,並非ServiceMesh。
(Sidecar本意是指跨鬥摩托車邊上的跨鬥,這裏指正式任務容器旁邊再附着一個管理的容器,組成服務網格。Sidecar用在這裏是很是形象的說法。)
Istio能夠在k8s上直接安裝,這個相愛相殺的世界啊:)
固然這個特徵是k8s的市場佔有率決定的,支持k8s能讓Istio更易用也有更多用戶。實際上Istio能夠在純Docker環境配合Docker Compose安裝,而且在沒有k8s存在的狀況下獨立運行。
在k8s集羣下安裝Istio,兩個產品的功能都能保留而且和平共處,不失爲一種好的解決方案。不少企業也是這樣作的。
依然建議你去官網仔細閱讀文檔https://istio.io/zh/docs/,Istio的中文文檔作的很是棒。 接下來是串講的簡化版本。
Istio也是分爲命令行控制工具和容器化的系統兩部分。安裝以前請先確認一下硬件配置,Docker+k8s+Istio所需最小的內存是4G,上一節咱們使用2G內存來學習k8s,如今是不夠用的。
在k8s的主控節點上安裝命令行工具及示例等:
$ curl -L https://git.io/getLatestIstio | sh -
getLatestIstio是官方提供的下載腳本,下載後自動執行,完成後,能夠把最新版本的CLI安裝於當前目錄。
隨後把Istio的程序目錄加入路徑:
//路徑設置.bashrc,從新登陸生效 echo "export PATH=$PATH:$PWD/istio-1.0.6/bin" >> ~/.profile //修改當前路徑設置 export PATH=$PATH:$PWD/istio-1.0.6/bin
接着是安裝Istio的主體部分:
//進入到Istio下載目錄,下面所使用的yaml文件都使用了相對路徑 $ cd istio-1.0.6/ //在k8s中自定義資源類型 $ kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io created customresourcedefinition.apiextensions.k8s.io/serviceentries.networking.istio.io created customresourcedefinition.apiextensions.k8s.io/gateways.networking.istio.io created customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io created customresourcedefinition.apiextensions.k8s.io/policies.authentication.istio.io created customresourcedefinition.apiextensions.k8s.io/meshpolicies.authentication.istio.io created customresourcedefinition.apiextensions.k8s.io/httpapispecbindings.config.istio.io created customresourcedefinition.apiextensions.k8s.io/httpapispecs.config.istio.io created customresourcedefinition.apiextensions.k8s.io/quotaspecbindings.config.istio.io created customresourcedefinition.apiextensions.k8s.io/quotaspecs.config.istio.io created customresourcedefinition.apiextensions.k8s.io/rules.config.istio.io created customresourcedefinition.apiextensions.k8s.io/attributemanifests.config.istio.io created customresourcedefinition.apiextensions.k8s.io/bypasses.config.istio.io created customresourcedefinition.apiextensions.k8s.io/circonuses.config.istio.io created customresourcedefinition.apiextensions.k8s.io/deniers.config.istio.io created customresourcedefinition.apiextensions.k8s.io/fluentds.config.istio.io created customresourcedefinition.apiextensions.k8s.io/kubernetesenvs.config.istio.io created customresourcedefinition.apiextensions.k8s.io/listcheckers.config.istio.io created customresourcedefinition.apiextensions.k8s.io/memquotas.config.istio.io created customresourcedefinition.apiextensions.k8s.io/noops.config.istio.io created customresourcedefinition.apiextensions.k8s.io/opas.config.istio.io created customresourcedefinition.apiextensions.k8s.io/prometheuses.config.istio.io created customresourcedefinition.apiextensions.k8s.io/rbacs.config.istio.io created customresourcedefinition.apiextensions.k8s.io/redisquotas.config.istio.io created customresourcedefinition.apiextensions.k8s.io/servicecontrols.config.istio.io created customresourcedefinition.apiextensions.k8s.io/signalfxs.config.istio.io created customresourcedefinition.apiextensions.k8s.io/solarwindses.config.istio.io created customresourcedefinition.apiextensions.k8s.io/stackdrivers.config.istio.io created customresourcedefinition.apiextensions.k8s.io/statsds.config.istio.io created customresourcedefinition.apiextensions.k8s.io/stdios.config.istio.io created customresourcedefinition.apiextensions.k8s.io/apikeys.config.istio.io created customresourcedefinition.apiextensions.k8s.io/authorizations.config.istio.io created customresourcedefinition.apiextensions.k8s.io/checknothings.config.istio.io created customresourcedefinition.apiextensions.k8s.io/kuberneteses.config.istio.io created customresourcedefinition.apiextensions.k8s.io/listentries.config.istio.io created customresourcedefinition.apiextensions.k8s.io/logentries.config.istio.io created customresourcedefinition.apiextensions.k8s.io/edges.config.istio.io created customresourcedefinition.apiextensions.k8s.io/metrics.config.istio.io created customresourcedefinition.apiextensions.k8s.io/quotas.config.istio.io created customresourcedefinition.apiextensions.k8s.io/reportnothings.config.istio.io created customresourcedefinition.apiextensions.k8s.io/servicecontrolreports.config.istio.io created customresourcedefinition.apiextensions.k8s.io/tracespans.config.istio.io created customresourcedefinition.apiextensions.k8s.io/rbacconfigs.rbac.istio.io created customresourcedefinition.apiextensions.k8s.io/serviceroles.rbac.istio.io created customresourcedefinition.apiextensions.k8s.io/servicerolebindings.rbac.istio.io created customresourcedefinition.apiextensions.k8s.io/adapters.config.istio.io created customresourcedefinition.apiextensions.k8s.io/instances.config.istio.io created customresourcedefinition.apiextensions.k8s.io/templates.config.istio.io created customresourcedefinition.apiextensions.k8s.io/handlers.config.istio.io created //安裝基本版本的Istio $ kubectl apply -f install/kubernetes/istio-demo.yaml namespace/istio-system created configmap/istio-galley-configuration created configmap/istio-grafana-custom-resources created configmap/istio-grafana-configuration-dashboards created configmap/istio-grafana created configmap/istio-statsd-prom-bridge created configmap/prometheus created configmap/istio-security-custom-resources created configmap/istio created configmap/istio-sidecar-injector created serviceaccount/istio-galley-service-account created serviceaccount/istio-egressgateway-service-account created serviceaccount/istio-ingressgateway-service-account created serviceaccount/istio-grafana-post-install-account created clusterrole.rbac.authorization.k8s.io/istio-grafana-post-install-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-grafana-post-install-role-binding-istio-system created job.batch/istio-grafana-post-install created serviceaccount/istio-mixer-service-account created serviceaccount/istio-pilot-service-account created serviceaccount/prometheus created serviceaccount/istio-cleanup-secrets-service-account created clusterrole.rbac.authorization.k8s.io/istio-cleanup-secrets-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-cleanup-secrets-istio-system created job.batch/istio-cleanup-secrets created serviceaccount/istio-security-post-install-account created clusterrole.rbac.authorization.k8s.io/istio-security-post-install-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-security-post-install-role-binding-istio-system created job.batch/istio-security-post-install created serviceaccount/istio-citadel-service-account created serviceaccount/istio-sidecar-injector-service-account created customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/serviceentries.networking.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/gateways.networking.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/httpapispecbindings.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/httpapispecs.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/quotaspecbindings.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/quotaspecs.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/rules.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/attributemanifests.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/bypasses.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/circonuses.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/deniers.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/fluentds.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/kubernetesenvs.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/listcheckers.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/memquotas.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/noops.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/opas.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/prometheuses.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/rbacs.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/redisquotas.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/servicecontrols.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/signalfxs.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/solarwindses.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/stackdrivers.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/statsds.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/stdios.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/apikeys.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/authorizations.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/checknothings.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/kuberneteses.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/listentries.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/logentries.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/edges.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/metrics.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/quotas.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/reportnothings.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/servicecontrolreports.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/tracespans.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/rbacconfigs.rbac.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/serviceroles.rbac.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/servicerolebindings.rbac.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/adapters.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/instances.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/templates.config.istio.io unchanged customresourcedefinition.apiextensions.k8s.io/handlers.config.istio.io unchanged clusterrole.rbac.authorization.k8s.io/istio-galley-istio-system created clusterrole.rbac.authorization.k8s.io/istio-egressgateway-istio-system created clusterrole.rbac.authorization.k8s.io/istio-ingressgateway-istio-system created clusterrole.rbac.authorization.k8s.io/istio-mixer-istio-system created clusterrole.rbac.authorization.k8s.io/istio-pilot-istio-system created clusterrole.rbac.authorization.k8s.io/prometheus-istio-system created clusterrole.rbac.authorization.k8s.io/istio-citadel-istio-system created clusterrole.rbac.authorization.k8s.io/istio-sidecar-injector-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-galley-admin-role-binding-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-egressgateway-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-ingressgateway-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-mixer-admin-role-binding-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-pilot-istio-system created clusterrolebinding.rbac.authorization.k8s.io/prometheus-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-citadel-istio-system created clusterrolebinding.rbac.authorization.k8s.io/istio-sidecar-injector-admin-role-binding-istio-system created service/istio-galley created service/istio-egressgateway created service/istio-ingressgateway created service/grafana created service/istio-policy created service/istio-telemetry created service/istio-pilot created service/prometheus created service/istio-citadel created service/servicegraph created service/istio-sidecar-injector created deployment.extensions/istio-galley created deployment.extensions/istio-egressgateway created deployment.extensions/istio-ingressgateway created deployment.extensions/grafana created deployment.extensions/istio-policy created deployment.extensions/istio-telemetry created deployment.extensions/istio-pilot created deployment.extensions/prometheus created deployment.extensions/istio-citadel created deployment.extensions/servicegraph created deployment.extensions/istio-sidecar-injector created deployment.extensions/istio-tracing created gateway.networking.istio.io/istio-autogenerated-k8s-ingress created horizontalpodautoscaler.autoscaling/istio-egressgateway created horizontalpodautoscaler.autoscaling/istio-ingressgateway created horizontalpodautoscaler.autoscaling/istio-policy created horizontalpodautoscaler.autoscaling/istio-telemetry created horizontalpodautoscaler.autoscaling/istio-pilot created service/jaeger-query created service/jaeger-collector created service/jaeger-agent created service/zipkin created service/tracing created mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector created attributemanifest.config.istio.io/istioproxy created attributemanifest.config.istio.io/kubernetes created stdio.config.istio.io/handler created logentry.config.istio.io/accesslog created logentry.config.istio.io/tcpaccesslog created rule.config.istio.io/stdio created rule.config.istio.io/stdiotcp created metric.config.istio.io/requestcount created metric.config.istio.io/requestduration created metric.config.istio.io/requestsize created metric.config.istio.io/responsesize created metric.config.istio.io/tcpbytesent created metric.config.istio.io/tcpbytereceived created prometheus.config.istio.io/handler created rule.config.istio.io/promhttp created rule.config.istio.io/promtcp created kubernetesenv.config.istio.io/handler created rule.config.istio.io/kubeattrgenrulerule created rule.config.istio.io/tcpkubeattrgenrulerule created kubernetes.config.istio.io/attributes created destinationrule.networking.istio.io/istio-policy created destinationrule.networking.istio.io/istio-telemetry created //驗證一下安裝的服務 $ kubectl get svc -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE grafana ClusterIP 10.99.63.62 <none> 3000/TCP 104s istio-citadel ClusterIP 10.97.149.61 <none> 8060/TCP,9093/TCP 103s istio-egressgateway ClusterIP 10.98.244.253 <none> 80/TCP,443/TCP 104s istio-galley ClusterIP 10.105.199.110 <none> 443/TCP,9093/TCP 105s istio-ingressgateway LoadBalancer 10.109.153.221 <pending> 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30607/TCP,8060:31625/TCP,853:30655/TCP,15030:32494/TCP,15031:31070/TCP 104s istio-pilot ClusterIP 10.108.220.116 <none> 15010/TCP,15011/TCP,8080/TCP,9093/TCP 104s istio-policy ClusterIP 10.101.97.253 <none> 9091/TCP,15004/TCP,9093/TCP 104s istio-sidecar-injector ClusterIP 10.103.63.166 <none> 443/TCP 103s istio-telemetry ClusterIP 10.107.184.81 <none> 9091/TCP,15004/TCP,9093/TCP,42422/TCP 104s jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 101s jaeger-collector ClusterIP 10.108.136.200 <none> 14267/TCP,14268/TCP 101s jaeger-query ClusterIP 10.105.46.4 <none> 16686/TCP 101s prometheus ClusterIP 10.102.94.141 <none> 9090/TCP 103s servicegraph ClusterIP 10.96.220.16 <none> 8088/TCP 103s tracing ClusterIP 10.105.46.106 <none> 80/TCP 101s zipkin ClusterIP 10.106.153.194 <none> 9411/TCP 101s //驗證執行的Pods: $ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE grafana-59b8896965-vlbd5 1/1 Running 0 89s istio-citadel-6f444d9999-cz6gk 1/1 Running 0 85s istio-cleanup-secrets-29mcx 0/1 Completed 0 91s istio-egressgateway-6d79447874-gzssf 1/1 Running 0 89s istio-galley-685bb48846-wx8q4 1/1 Running 0 89s istio-grafana-post-install-gkz6g 0/1 Completed 0 91s istio-ingressgateway-5b64fffc9f-f8h2q 1/1 Running 0 89s istio-pilot-7f558fc848-jtrqs 2/2 Running 0 88s istio-policy-547d64b8d7-br5cn 2/2 Running 0 88s istio-security-post-install-xz5xd 0/1 Completed 0 91s istio-sidecar-injector-5d8dd9448d-m4lls 1/1 Running 0 83s istio-telemetry-c5488fc49-g5vjw 2/2 Running 0 88s istio-tracing-6b994895fd-6hwqv 1/1 Running 0 82s prometheus-76b7745b64-gpdkw 1/1 Running 0 88s servicegraph-cb9b94c-7sjks 1/1 Running 0 83s
從Pods狀態中,若是有不是Running的,能夠使用kubectl describe子命令查看詳細狀態,並找出錯誤緣由。例如:kubectl -n istio-system describe pods istio-pilot。
基礎軟硬件環境在安裝k8s的時候等於通過了驗證,因此一般碰到的問題都是由於網絡緣由映像沒法下載。Completed狀態的通常是依賴包未能運行致使的退出,這種會自動嘗試重啓。或者是隻須要安裝時執行一次的容器。正常狀況都不須要管。
Istio多是發佈時間尚短,國內沒有能找到比較好的鏡像,因此下載比較慢。我整理了一下須要的鏡像列表,建議網絡環境不理想的,在正式安裝Istio以前,先使用root權限在Docker中完成鏡像的下載,而後再執行上述安裝。
docker pull docker.io/istio/proxy_init:1.0.6 docker pull docker.io/istio/proxyv2:1.0.6 docker pull quay.io/coreos/hyperkube:v1.7.6_coreos.0 docker pull docker.io/istio/galley:1.0.6 docker pull grafana/grafana:5.2.3 docker pull docker.io/istio/mixer:1.0.6 docker pull docker.io/istio/pilot:1.0.6 docker pull docker.io/prom/prometheus:v2.3.1 docker pull docker.io/istio/citadel:1.0.6 docker pull docker.io/istio/servicegraph:1.0.6 docker pull docker.io/istio/sidecar_injector:1.0.6 docker pull docker.io/jaegertracing/all-in-one:1.5
Istio的安裝就這樣兩步,使用容器以來,軟件的安裝和配置變得愈來愈便利。
//順便,在k8s環境中安裝Istio以後,嘗試列表全部的系統級Pods,也是很壯觀的一坨 //不過在微服務的理念下,其實一個容器每每就是一個進程,整體耗費資源並很少 $ kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE istio-system grafana-59b8896965-vlbd5 1/1 Running 2 17h istio-system istio-citadel-6f444d9999-cz6gk 1/1 Running 2 17h istio-system istio-egressgateway-6d79447874-gzssf 1/1 Running 2 17h istio-system istio-galley-685bb48846-4f9qq 1/1 Running 1 16m istio-system istio-ingressgateway-5b64fffc9f-lqjjv 1/1 Running 1 16m istio-system istio-pilot-7f558fc848-mts8g 2/2 Running 2 16m istio-system istio-policy-547d64b8d7-br5cn 2/2 Running 4 17h istio-system istio-sidecar-injector-5d8dd9448d-ftsrr 1/1 Running 1 16m istio-system istio-telemetry-c5488fc49-gpdx5 2/2 Running 2 16m istio-system istio-tracing-6b994895fd-6hwqv 1/1 Running 2 17h istio-system prometheus-76b7745b64-gpdkw 1/1 Running 2 17h istio-system servicegraph-cb9b94c-7sjks 1/1 Running 4 17h kube-system calico-node-sjdcg 2/2 Running 24 5d21h kube-system coredns-78d4cf999f-pg4mn 1/1 Running 12 5d21h kube-system coredns-78d4cf999f-zsh76 1/1 Running 12 5d21h kube-system etcd-userver-master 1/1 Running 12 5d21h kube-system kube-apiserver-userver-master 1/1 Running 13 5d21h kube-system kube-controller-manager-userver-master 1/1 Running 15 5d21h kube-system kube-proxy-fx42f 1/1 Running 12 5d21h kube-system kube-scheduler-userver-master 1/1 Running 14 5d21h kube-system kubernetes-dashboard-57df4db6b-5vmqk 1/1 Running 1 16m
上面說過,Istio的基本原理是在每一個Pods中增長Sidecar來完成對Pods全部數據流量的代理,並以此來達成各項附加的功能。
因此在正式任務以前,咱們先作一個設置,讓k8s每次啓動容器的時候,自動完成Istio Sidercar的注入,這樣一來,咱們原有的Pods配置文件,無需修改,自動就會獲得Istio提供的各項功能:
kubectl label namespace default istio-injection=enabled
這一行就是爲默認的default命名空間增長istio sidecard注入功能。若是但願爲其它命名空間添加自動注入,把上面命令中的default換成你但願的命名空間的名字。
查看哪些命名空間打開了自動注入,能夠使用命令:
kubectl get namespace -L istio-injection
單純從命令行角度來看,使用Istio同使用基本的k8s彷佛沒有什麼區別。
實際上Istio也是使用配置文件來啓動容器。Istio在配置文件中,提供了大量本身特有的配置指令,從而提供服務網格的特徵和功能。
做爲對比,咱們來看一個使用Istio啓動容器的配置文件實例:
apiVersion: v1 kind: Service metadata: name: istio-dog labels: app: istio-dog service: istio-dog spec: ports: - port: 5678 name: http selector: app: istio-dog --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: istio-dog-v1 labels: app: istio-dog version: v1 spec: replicas: 1 template: metadata: labels: app: istio-dog version: v1 spec: containers: - name: istio-dog image: hashicorp/http-echo args: - "-text=istio-dog-v1" imagePullPolicy: IfNotPresent ports: - containerPort: 5678 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: istio-dog-v2 labels: app: istio-dog version: v2 spec: replicas: 1 template: metadata: labels: app: istio-dog version: v2 spec: containers: - name: istio-dog image: hashicorp/http-echo args: - "-text=istio-dog-v2" imagePullPolicy: IfNotPresent ports: - containerPort: 5678 --- apiVersion: v1 kind: Service metadata: name: istio-cat labels: app: istio-cat service: istio-cat spec: ports: - port: 5678 name: http selector: app: istio-cat --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: istio-cat-v1 labels: app: istio-cat version: v1 spec: replicas: 1 template: metadata: labels: app: istio-cat version: v1 spec: containers: - name: istio-cat image: hashicorp/http-echo args: - "-text=istio-cat-v1" imagePullPolicy: IfNotPresent ports: - containerPort: 5678
Istio官方提供了Bookinfo示例做爲入門教程,全部配套文檔均有中文版,示例和文檔寫的都很棒。站在運維人員角度看,Bookinfo示例略顯門檻偏高,因此我使用本身寫的示例來演示、入門。
上面的配置文件中,定義了兩個服務和三個Pod,其中istio-dog定義了兩個版本。版本化是A/B測試和紅黑髮布的必須功能,也是咱們前面說過的k8s的弱項。
Pod定義的部分,使用不同的類型Deployment。實際上區別同Pod類型並不大,看起來應當不困難。服務部分,單純從指令上跟前面k8s的示例沒有區別,可是咱們並無定義服務類型好比NodePort。這是由於,咱們使用的是Istio服務網格,雖然運行在k8s環境下,但並不須要k8s的網絡代理功能。
前面說過,智能的流量控制是Istio第一大基本功能。理解並使用這一功能,須要先介紹一下作Istio流量控制的主要路徑:
瞭解了這個機制,咱們看一個網絡設置的示例:
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-test-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: istio-test spec: hosts: - "*" gateways: - istio-test-gateway http: - match: - uri: exact: /cat-and-dog route: - destination: host: istio-dog port: number: 5678
配置文件中首先定義了一個Gateway,端口號80,特別注意一下其中的protocol指令,定義了HTTP協議。這一點跟k8s是有比較大的區別的,雖然你可能認爲是理所固然的。緣由是Istio是使用Sidecar全面代理做爲核心來實現全部功能的,既然是代理,而且須要流經的數據進行解析,因此必然對可識別的協議類型是有限制的。這一點同k8s的端口映射實際有根本的區別。
配置文件中又定義了一個虛擬服務,從Gateway過來的流量中,若是路徑匹配/cat-and-dog,則將流量導入到istio-dog服務。注意host容易讓人誤解,這裏實際就是Service名,k8s中也是同樣的。
咱們把兩個配置文件,分別保存爲好比istio-test.yaml和istio-test-gateway1.yaml,而後執行來測試一下。
$ kubectl apply -f istio-test.yaml service/istio-dog created deployment.extensions/istio-dog-v1 created deployment.extensions/istio-dog-v2 created service/istio-cat created deployment.extensions/istio-cat-v1 created $ kubectl apply -f istio-test-gateway1.yaml gateway.networking.istio.io/istio-test-gateway created virtualservice.networking.istio.io/istio-test created $ kubectl get VirtualServices NAME AGE istio-test 25s $ kubectl get Gateways NAME AGE istio-test-gateway 3m $ kubectl get pods NAME READY STATUS RESTARTS AGE istio-cat-5fdcfd9fcd-bncmm 2/2 Running 0 3m57s istio-dog-v1-657d697cd8-pdm7w 2/2 Running 0 3m57s istio-dog-v2-69f6bb9dd8-wx8f7 2/2 Running 0 3m57s //注意運行在Istio中的服務並不須要導出端口 $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-cat ClusterIP 10.106.214.198 <none> 80/TCP 4m24s istio-dog ClusterIP 10.106.22.195 <none> 80/TCP 4m24s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d
不一樣於k8s,Istio已經預先導出了80/443端口,這是由istio-ingressgateway服務來完成的:
$ kubectl get svc istio-ingressgateway -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.98.100.87 <pending> 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30050/TCP,8060:32063/TCP,853:31120/TCP,15030:30238/TCP,15031:30782/TCP 20h
一般80端口都是映射到31380,使用k8s的節點IP和31380端口就能夠訪問咱們的測試應用。這個端口號能夠經過修改istio-ingressgateway服務來修改。
爲了體現咱們的流量分配效果,咱們再添加一個腳本文件,好比run100.sh:
#!/bin/sh for i in `seq 100`; do curl 127.0.0.1:31380/cat-and-dog done
執行測試腳本:
$ ./run100.sh istio-dog-v2 istio-dog-v1 istio-dog-v2 istio-dog-v1 istio-dog-v1 istio-dog-v2 ...略
咱們並無在虛擬服務中指定更詳細的流量策略,因此兩個istio-dog容器是分別提供服務的,基本各佔50%流量。這個流量分配並非虛擬服務提供的,而是基本Service。
咱們再來看看另一種配置方式:
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-test-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: istio-test spec: hosts: - "*" gateways: - istio-test-gateway http: - match: - uri: exact: /dog route: - destination: host: istio-dog - match: - uri: exact: /cat route: - destination: host: istio-cat
配置文件保存爲istio-test-gateway2.yaml。在執行新的網絡配置前,記着先刪除掉舊的:
$ kubectl delete -f istio-test-gateway1.yaml gateway.networking.istio.io "istio-test-gateway" deleted virtualservice.networking.istio.io "istio-test" deleted $ kubectl apply -f istio-test-gateway2.yaml gateway.networking.istio.io/istio-test-gateway created virtualservice.networking.istio.io/istio-test created
此時,訪問根據路徑不一樣,分配到兩個不一樣的服務,再到3個Pods:
$ curl http://127.0.0.1:31380/dog istio-dog-v2 $ curl http://127.0.0.1:31380/dog istio-dog-v2 $ curl http://127.0.0.1:31380/dog istio-dog-v1 $ curl http://127.0.0.1:31380/cat istio-cat-v1 $ curl http://127.0.0.1:31380/cat istio-cat-v1
再來看一個:
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-test-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: istio-test spec: hosts: - "*" gateways: - istio-test-gateway http: - match: - uri: exact: /cat-and-dog route: - destination: host: istio-dog weight: 20 - destination: host: istio-cat weight: 80
保存配置到文件:istio-test-gateway3.yaml。刪除上一版的配置,應用新的配置:
$ kubectl delete -f istio-test-gateway2.yaml gateway.networking.istio.io "istio-test-gateway" deleted virtualservice.networking.istio.io "istio-test" deleted $ kubectl apply -f istio-test-gateway3.yaml gateway.networking.istio.io/istio-test-gateway created virtualservice.networking.istio.io/istio-test created
此次是使用權重值,分配到兩個服務的流量比例,到istio-dog的是20%,到istio-cat的是80%。看一看測試的結果:
$ ./run100.sh istio-cat-v1 istio-cat-v1 istio-dog-v1 istio-dog-v2 istio-cat-v1 istio-cat-v1 istio-cat-v1 istio-cat-v1 istio-cat-v1 istio-cat-v1 istio-dog-v1 istio-cat-v1 istio-cat-v1 istio-cat-v1 istio-dog-v2 ...
好吧,我認可我故意誤導了各位。其實apply子命令的真諦自己就在於對於同類型中同名的對象,好比咱們上面定義的VirtualService中的istio-test。對於新的配置,在應用時並不須要刪除原來的定義,k8s和Istio都會自動的更新配置。在這個過程當中,對外的服務並無中斷。
由於有了這樣的機制,才能夠實現老版本、新版本並行運行,新版本測試結束後,直接取代老版本的服務完成升級這樣的需求。
我這裏每次都強調刪除上一個配置,實際是強調,若是是兩個不一樣的應用,前一個不使用了,記着必定要回收資源,而且避免端口衝突。
你能夠試試直接應用另一個配置文件來測試一下,感覺一下不停機更新的快樂吧。
在容器內,訪問其它容器的服務,一樣是使用基於DNS的服務名稱,好比:istio-cat.default.svc.cluster.local,這個跟k8s是徹底一致的。
能夠參考官方Bookinfo案例的python源碼。安裝Istio命令行時候的下載包中只有yaml配置文件,python程序的源碼及Dockerfile源碼須要到官方github倉庫中檢索。想要完全瞭解運維、研發跟Istio的配合,建議讀一讀源碼。做爲示例性的源碼,代碼量很短,註釋也比較全,很是便於理解。倉庫地址:https://github.com/istio/istio/tree/master/samples/bookinfo/src
掌握了上面所說的概念,看過了本文中的示例,如今去看官方關於Bookinfo部分的教程不該當有問題了,建議及早開始,網址在本小節開始的部分給出了。
執行Bookinfo示例,由於網絡緣由,建議首先root狀態使用docker提早下載映像文件。由於這種小衆的映像,國內更是難以找到鏡像網站,官方下載速度很慢:
docker pull istio/examples-bookinfo-details-v1:1.8.0 docker pull istio/examples-bookinfo-ratings-v1:1.8.0 docker pull istio/istio/examples-bookinfo-reviews-v1:1.8.0 docker pull istio/examples-bookinfo-reviews-v2:1.8.0 docker pull istio/examples-bookinfo-reviews-v3:1.8.0 docker pull istio/examples-bookinfo-productpage-v1:1.8.0
在Istio安裝的過程當中,已經預置了Prometheus和Grafana指標可視化工具,使用Kubectl工具的端口轉發功能把服務端口開放出來就能夠使用,好比:
$ kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=prometheus -o jsonpath='{.items[0].metadata.name}') --address 0.0.0.0 9090:9090 & $ kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') --address 0.0.0.0 3000:3000 &
上面兩條轉發命令中的--address 0.0.0.0
是爲了把端口開放給節點主機以外的電腦來訪問,由於一般節點服務器上不具有圖形界面。但這也會帶來安全性的問題,因此注意要使用完即時關閉。
這部分請參考官方文檔:https://istio.io/zh/docs/tasks/telemetry/metrics/querying-metrics/
Istio在輔助調試方面,能夠在流量中注入指定的錯誤信息、對數據包進行延遲、中斷等,用於模擬實際故障發生的可能性,從而幫助研發人員、運維人員對系統進行優化。具體使用方法請參考官方文檔。
監控功能和輔助調試一樣也是藉助了Sidecar對全部數據流的代理功能得以實現的。
在安全性方面,Istio主要是採用證書籤名機制和TLS鏈接。支持TLS鏈接的版本,同本文中咱們示例安裝的版本不是同一個。若是有需求,請在Istio集羣安裝時就注意選擇對應的配置文件來啓動。詳情請至官方文檔學習。
Istio的使用實驗中,每一個配置實驗完成,若是配置再也不須要,記着使用kubectl delete -f xxx.yaml的方式來刪除。由於不一樣於k8s的隨機映射端口出來,Istio一般都使用默認導出的80或者443端口。這樣不一樣配置之間忘記刪除不免會形成衝突。這時候能夠手工刪除,能夠參考一下Bookinfo中的 samples/bookinfo/platform/kube/cleanup.sh 腳本。基本作法是使用kubectl get遍歷下面三類對象:
destinationrules virtualservices gateways,其中的內容所有刪除。
本文以用戶需求的演進爲導向,面向實際應用串講了服務器端企業級運維的流行技術和流行概念。 重點介紹了Docker/k8s/Istio的安裝、典型使用的入門。 水平所限,錯誤、疏漏在所不免,歡迎批評指正。