都9102年了,還不會Docker?10分鐘帶你從入門操做到實戰上手

Docker簡述

Docker是一種OS虛擬化技術,是一個開源的應用容器引擎。它可讓開發者將應用打包到一個可移植的容器中,而且該容器能夠運行在幾乎全部linux系統中(Windows10目前也原生支持,Win10前須要內置虛擬機),正所謂「一次打包,處處運行」。前端

Docker容器的運行是徹底的沙箱機制,相互之間不會有任何關聯(除非本身串聯集羣)。網絡、存儲、進程等資源,不只對於不一樣的容器是相互隔離,對於宿主機和容器直接也是隔離的,除非你手動映射暴露端口或者掛載存儲卷。linux

不少人不理解,Docker和虛擬機到底有什麼區別。 git

從這兩張結構圖來看,Docker比虛擬機少了一層虛擬機操做系統,Docker的應用直接Docker引擎上運行。因爲虛擬機須要一層操做系統,因此會致使虛擬機的體積很是大,一般在幾G到十幾G之間。而且一般一個虛擬機上,不僅一個應用,所以對於總體的虛擬集羣管理並不太友好,比較難作到靈活分配。

而一個Docker鏡像的體積大約在幾十M到幾百M之間,通常一個鏡像只打包一個應用,由多個鏡像組成一個完整的項目,而且鏡像易於複製,能夠跨平臺運行,這樣可使項目的部署管理有更好的靈活性。因此Docker不管從資源消耗上、管理上、使用上都在虛擬機之上,所以咱們又有何理由不使用這樣的容器化技術呢?github

對於容器化技術的學習,可謂是深如海。從基本的鏡像、容器操做,到鏡像的打包、容器的部署,再到企業生產級的容器集羣管理技術(Docker官方的Swarm、Google的Kubernetes),如此多的內容,並非全部人技術人員都能一朝學會。不過除了生產級別的集羣管理技術有難度意外,其餘內容從學習使用的角度來講,實際上是很是簡單的,何況K8s這種東西,對於普通開發來講也是不多能接觸到。redis

說到這裏,可能還有不少人以爲這個是公司層面、運維層面的操做,不是很瞭解Docker對於普通開發來講,意味着什麼,對咱們有什麼好處?sql

  • 多辦公環境,一鍵部署。假如你在公司一套開發環境,在家一套開發環境,當你公司的開發環境變動時,在家的環境就要跟着變,若是是使用Docker,將一些依賴型的應用,如Redis、ZK、Mysql等邊緣服務都打包在docker裏面。不管你在哪裏改變了內容,只要在運行時更新下鏡像,就能夠按照最新的內容去執行了,不須要一個手動去安裝,適配。
  • 聯調測試,無需依賴他人。當後端完成對外的接口後,將後端應用打包進docker,這樣不管是前端、測試,在何地什麼時候均可以本身把容器啓動起來進行聯調測試,而不須要本身手動一步步地搭建這個後端環境。
  • ...

下面就來一步步講解下,普通開發所須要的Docker知識。mongodb

概念介紹

學習Docker首先要了解下幾個基礎概念:docker

  • 宿主機,Host,運行Docker所在的物理機,是Docker運行的系統環境。
  • 鏡像,Image,至關於一個程序模板,經過這個模板能夠生成不少個類似的容器。能夠理解爲Java中的類,它自己不具有執行運行的能力,是一個對象抽象的模板。每一個鏡像能夠有多個版本,用tag來區分。鏡像能夠經過Dockerfile來構建。
  • 容器,Container,Docker運行的最小單位對象。它是經過鏡像實例化出來的一個可運行對象。容器的修改,能夠提交副作用於鏡像,更新這個容器的模板。
  • 倉庫,Repository,用於存儲管理鏡像的倉庫,相似於git管理代碼的倉庫同樣,能夠管理多版本的鏡像。

鏡像、容器、倉庫的關係以下: ubuntu

一句話總結就是,從倉庫中拉取鏡像,利用鏡像生成容器。

基本操做

瞭解完Docker的基本概念,咱們開始來開始學習下入門操做。此處省略全部的Docker安裝過程,本身去官網下載就好了,基本是傻瓜式安裝。後端

拉取鏡像

經過docker pull ${image_uri}:${image_tag}命令,能夠從遠程倉庫(默認是Docker Hub)中拉取所須要的鏡像。

Docker Hub的網站上能夠搜索下本身須要的鏡像以及版本。例如Ubuntu,上面提供了幾個版本。

咱們拉一下 16.04版本的ubuntu鏡像。而後經過 docker images命令,查看保存在本地鏡像,發現多了一個ubuntu的鏡像。

容器建立、啓動、中止、登入

有了鏡像之後,就能夠經過docker run -it ${image_id}建立啓動一個容器了。

image_id是鏡像的id,經過docker images能查看到,也能夠是鏡像名(REPOSITORY:TAG)。

-it可讓你在啓動後,連上容器的終端。連上終端後,就能夠在裏面隨意操做容器裏面的內容了。

exit退出容器後,容器就會自動中止了。可是這個容器依然還存在,只是」關機「了。(能夠經過ctrl+p,ctrl+q,退出容器登入,而不關閉容器)

經過docker ps -a能夠看到咱們的容器已經Exited了。

經過docker start ${container_id},咱們把這個容器再次啓動。經過docker ps(加上*-a包含顯示未啓動的容器),能夠看到容器的狀態爲UP*。

同理,咱們能夠經過docker stop ${container_id}來中止容器,

在用docker start命令的時候,若是不加上*-a*參數,默認不會鏈接上容器的。不過咱們能夠在start後,經過docker attach ${container_id}來登入容器。

經過以上的基本操做,你基本能夠利用docker看成一個虛擬機來使用了。若是想把容器和虛擬機的網絡、存儲打通,能夠網上搜下了解下網絡與卷掛載等容器設置。

更新鏡像

在上面的例子中,咱們pull下來的僅僅是一個ubuntu的原始鏡像,並無過多的內容。下面咱們在這個鏡像的容器裏面,安裝一個jdk。

這樣咱們的容器裏面就有一個jdk了,可是若是咱們再用這個ubuntu原始鏡像再建立一個容器,它是不會用這個jdk的。因此咱們就須要把這個容器的內容,提交到鏡像當中。

經過docker commit ${container_id} ${repository}:${tag},在本地將容器內容提交到鏡像當中。而後就能夠擁有一個帶jdk的ubuntu鏡像了。

後面咱們就能夠利用這個鏡像,生成帶jdk的容器了。

以上的更新僅限於在本地的鏡像,若是想把容器推送到雲端就須要用docker push命令。前提是你已經登陸了倉庫擁有權限。

鏡像倉庫

上面提到,默認狀況下,倉庫是用Docker Hub。咱們pull 和push都是在Docker hub上操做,可是若是鏡像是內部私有使用的話,沒有必要去使用Docker Hub,一個是網絡慢,另外一個是私有安全性問題。

針對以上問題,有兩種解決方法,一個是本身搭建私有服務,另外一個是用雲服務的鏡像管理平臺(如阿里雲的「容器鏡像服務」)。前者對於通常開發者來講並無必要,並且還要搞認證的,比較麻煩,這裏不細說。下面介紹下如何用阿里雲服務做爲本身的私有倉庫。

先在阿里雲上建立一個鏡像倉庫,得到一個倉庫地址,如registry.cn-shenzhen.aliyuncs.com/zackku/jdk。這裏一個倉庫地址,對應一種鏡像(tag不一樣)。

利用docker login,先對阿里雲的服務進行登陸。

而後對上面的jdk鏡像打tag(其實也是改倉庫源的過程)

最後把鏡像推送到阿里雲就好了。

推送後,就能在阿里雲的倉庫上看到這個鏡像。

經過搭建私有倉庫,咱們就能夠徹底拋開宿主機的環境,構建好一個鏡像,就能夠處處運行了。

Dockerfile構建鏡像

從上面介紹,咱們已經瞭解到,如何從拉取一個鏡像、修改容器內容、提交鏡像去構建一個咱們所須要的鏡像。但經過這些操做去構建一個鏡像,一個是太繁瑣,另外一個問題是不清晰,沒辦法直觀的瞭解鏡像的構成。

Dockerfile就能夠很好的解決該問題。它能夠經過編寫一個構建過程,來一站式構建鏡像。下面一樣以ubuntu爲基礎鏡像,安裝jdk構建一個新鏡像爲例,看看Dockerfile是怎麼寫的。

而後執行docker build -t registry.cn-shenzhen.aliyuncs.com/zackku/jdk2:1.0 .就能把鏡像構建出來了。

Dockerfile高級技巧

上面是Dockerfile的基本使用,但實際狀況下咱們並不像(或者說不只是)上面描述那樣去構建鏡像。下面介紹兩個經常使用的使用原則。

分層構建。其實Docker的鏡像是分層結構的,看回以前推送到遠端倉庫的例子。

紅框裏面就是鏡像一層層的提交,若是這層已經本地構建過了,下次不須要構建了,同理若是遠端已經有這層了,也不須要推送這層。並且這種分層是能夠在不一樣鏡像間共享的,例如不一樣的Java項目都是依賴於JDK的運行環境,那麼它們就能夠共用JDK這層鏡像內容。

因此,基於這樣的特性,咱們就應該要分層去構建鏡像,抽象鏡像共同點。具體操做的話,咱們大體能夠去分兩次構建鏡像,先構建一個base鏡像,用於不一樣鏡像的底層,例如Java項目的全部基礎運行環境,而後再經過base鏡像,構建develop表層的應用鏡像。至關於把應用程序打包丟到develop層裏面。而且這層要告訴Docker是怎麼運行程序的。

儘可能構建小的base層。鏡像的體積也是在使用Docker的時候要考慮的一個重要因素,由於若是鏡像的體積過大,在更新鏡像,拉取鏡像的時候效率會低。尤爲在剛剛所說的base層裏面,若是base層作得太大太臃腫,裏面程序過多,不只僅體積大,還會讓CPU、網絡等資源消耗過大。其實咱們在用Docker的時候,通常是一個容器只包含一個程序項目,關於這個程序的監控、健康等內容,在容器外經過k8s等集羣管理去作,因此容器自己只須要保證本身的程序可以運行起來就好了。

至於上面我用ubuntu做爲基礎的操做系統是比較多餘的,這裏推薦只用apline操做系統做爲程序的最底層鏡像,它是一款輕型的Linux發行版,系統體積與運行時的資源消耗都至關低,十分適合用於Docker容器。基於apline的操做系統,咱們在上面添加本身所須要的環境,例如安裝一個Tomcat、JDK等,從而構建一個base的鏡像。

上所說的base鏡像,其實不太須要本身的寫一層Dockfile,docker官方就直接提供了各類語言、環境的基礎鏡像,在github的docker-library裏面。若是再有本身的團隊的運行環境的要求,能夠在這個Dockerfile基礎上去添加修改便可,或者再抽象多一層。

至於Dockfile怎麼寫,語法是什麼,網上有大把詳細的說明,因爲篇幅問題,不在這裏展開。

docker-compose啓動集羣

前面已經介紹完一個單獨的容器是如何構建與啓動的了,但咱們的項目每每不是隻有一個容器的,把全部程序打包在一個容器不是正確的作法。因此咱們怎麼去管理啓動這麼多的容器,是一個必修的課題。在企業級的層面,有K8S,Swarm這種容器編排的管理工具,但稍微比較複雜,我的使用的話也沒有太大必要。

這裏推薦用Docker官方的docker-compose,它能夠把全部的容器編排方式寫在一個文件裏,而後經過docker-compose up命令,就能夠把一套的容器按照你的編排所有啓動起來。

在這個例子的services包含每一個容器的配置,其中的redis、mongodb用的是默認的鏡像、默認的配置,myproject是咱們本身的項目。經過這樣的編排,咱們就能讓咱們的項目連上redis和mongodb。最後經過docker-compose up就會自動拉取鏡像,按照編排跑起來了。

具體的語法也不贅述,關鍵就是容器的卷掛載,網絡的配置,端口的暴露,容器的依賴關係。若是把這套東西用起來,慢慢天然就會了解,重要的是動手去作一遍,嘗試一下。


更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼

相關文章
相關標籤/搜索