Docker技術入門

jopen 9年前發布 | 57K 次閱讀 Docker

原文  http://starlight36.com/post/startup-to-docker


關注Docker這項技術差不多一年多了,最近關于Docker的使用案例越來越多,于是就想動手實驗下這項技術。自己整理了一個入門手冊,分享給大家。

Docker是什么

Docker是一種容器技術,它可以將應用和環境等進行打包,形成一個獨立的,類似于iOS的APP形式的“應用”,這個應用可以直接被分發到任 意一個支持Docker的環境中,通過簡單的命令即可啟動運行。Docker是一種最流行的容器化實現方案。和虛擬化技術類似,它極大的方便了應用服務的 部署;又與虛擬化技術不同,它以一種更輕量的方式實現了應用服務的打包。使用Docker可以讓每個應用彼此相互隔離,在同一臺機器上同時運行多個應用, 不過他們彼此之間共享同一個操作系統。Docker的優勢在于,它可以在更細的粒度上進行資源的管理,也比虛擬化技術更加節約資源。

Docker技術入門 虛擬化和Docker架構對比,來自Docker官網

基本概念

開始試驗Docker之前,我們先來了解一下Docker的幾個基本概念:

鏡像:我們可以理解為一個預配置的系統光盤,這個光盤插入電腦后就可以啟動一個操作系統。當然由于是光盤,所以你無法修改它或者保存數據,每次重啟都是一個原樣全新的系統。Docker里面鏡像基本上和這個差不多。

容器:同樣一個鏡像,我們可以同時啟動運行多個,運行期間的產生的這個實例就是容器。把容器內的操作和啟動它的鏡像進行合并,就可以產生一個新的鏡像。

開始

Docker基于 LXC 技術實現,依賴于Linux內核,所以Docker目前只能在Linux以原生方式運行。目前主要的Linux發行版在他們的軟件倉庫中內置了Docker:

Ubuntu:

  • Ubuntu Trusty 14.04 (LTS)
  • Ubuntu Precise 12.04 (LTS)
  • Ubuntu Saucy 13.10
  • </ul>

    CentOS:

    • CentOS 7
    • </ul>

      Docker要求64位環境,這些操作系統下可以直接通過命令安裝Docker,老一些操作系統Docker官方也提供了安裝方案。下面的實驗基于CentOS 7進行。關于其他版本操作系統上Docker的安裝,請參考官方文檔: https://docs.docker.com/installation/

      在CentOS 7上安裝Docker

      使用yum從軟件倉庫安裝Docker:

      Shell

      </div>

      yum install docker
      </div>

      首先啟動Docker的守護進程:

      Shell

      </div>

      service docker start
      </div>

      如果想要Docker在系統啟動時運行,執行:

      Shell

      </div>

      chkconfig docker on
      </div>

      Docker在CentOS上好像和防火墻有沖突,應用防火墻規則后可能導致Docker無法聯網,重啟Docker可以解決。

      Docker倉庫

      Docker使用類似git的方式管理鏡像。通過基本的鏡像可以定制創建出來不同種應用的Docker鏡像。 Docker Hub 是Docker官方提供的鏡像中心。在這里可以很方便地找到各類應用、環境的鏡像。

      由于Docker使用聯合文件系統,所以鏡像就像是夾心餅干一樣一層層構成,相同底層的鏡像可以共享。所以Docker還是相當節約磁盤空間的。要使用一個鏡像,需要先從遠程的鏡像注冊中心拉取,這點非常類似git。

      Shell

      </div>

      docker pull ubuntu
      </div>

      我們很容易就能從Docker Hub鏡像注冊中心下載一個最新版本的ubuntu鏡像到本地。國內網絡可能會稍慢, DaoCloud 提供了Docker Hub的國內加速服務,可以嘗試配置使用。

      運行一個容器

      使用Docker最關鍵的一步就是從鏡像創建容器。有兩種方式可以創建一個容器:使用docker create命令創建容器,或者使用docker run命令運行一個新容器。兩個命令并沒有太大差別,只是前者創建后并不會立即啟動容器。

      以ubuntu為例,我們啟動一個新容器,并將ubuntu的Shell作為入口:

      Shell

      </div>

      docker run -it ubuntu:latest sh -c '/bin/bash'
      </div>

      這時候我們成功創建了一個Ubuntu的容器,并將當前終端連接為這個Ubuntu的bash shell。這時候就可以愉快地使用Ubuntu的相關命令了~可以快速體驗一下。

      參數-i表示這是一個交互容器,會把當前標準輸入重定向到容器的標準輸入中,而不是終止程序運行。-t指為這個容器分配一個終端。

      好了,按Ctrl+D可以退出這個容器了。

      在容器運行期間,我們可以通過docker ps命令看到所有當前正在運行的容器。添加-a參數可以看到所有創建的容器:

      Shell

      </div>

      docker ps -a
      [root@localhost ~]# docker ps -a
      CONTAINER ID        IMAGE                        COMMAND                CREATED             STATUS                      PORTS               NAMES
      cb2b06c83a50        ubuntu:latest                "sh -c /bin/bash"      7 minutes ago       Exited (0) 7 seconds ago                        trusting_morse

      </div>

      每個容器都有一個唯一的ID標識,通過ID可以對這個容器進行管理和操作。在創建容器時,我們可以通過–name參數指定一個容器名稱,如果沒有指定系統將會分配一個,就像這里的“trusting_morse”(什么鬼。。)。

      當我們按Ctrl+D退出容器時,命令執行完了,所以容器也就退出了。要重新啟動這個容器,可以使用docker start命令:

      Shell

      </div>

      docker start -i trusting_morse
      </div>

      同樣,-i參數表示需要交互式支持。

      注意:每次執行docker run命令都會創建新的容器,建議一次創建后,使用docker start/stop來啟動和停用容器。

      存儲

      在Docker容器運行期間,對文件系統的所有修改都會以增量的方式反映在容器使用的聯合文件系統中,并不是真正的對只讀層數據信息修改。每次運 行容器對它的修改,都可以理解成對夾心餅干又添加了一層奶油。這層奶油僅供當前容器使用。當刪除Docker容器,或通過該鏡像重新啟動時,之前的更改將 會丟失。這樣做并不便于我們持久化和共享數據。Docker的數據卷這個東西可以幫到我們。

      在創建容器時,通過-v參數可以指定將容器內的某個目錄作為數據卷加載:

      Shell

      </div>

      docker run -it -v /home/www ubuntu:latest sh -c '/bin/bash'
      </div>

      在容器中會多一個/home/www掛載點,在這個掛載點存儲數據會繞過聯合文件系統。我們可以通過下面的命令來找到這個數據卷在主機上真正的存儲位置:

      Shell

      </div>

      docker inspect -f {{.Volumes}} trusting_morse
      </div>

      你會看到輸出了一個指向到/var/lib/docker/vfs/dir/…的目錄。cd進入后你會發現在容器中對/home/www的讀寫創建,都會反映到這兒。事實上,/home/www就是掛載自這個位置。

      有時候,我們需要將本地的文件目錄掛載到容器內的位置,同樣是使用數據卷這一個特性,-v參數格式為:

      Shell

      </div>

      docker run -it -v [host_dir]:[container_dir]
      </div>

      host_dir是主機的目錄,container_dir是容器的目錄。

      容器和容器之間是可以共享數據卷的,我們可以單獨創建一些容器,存放如數據庫持久化存儲、配置文件一類的東西,然而這些容器并不需要運行。

      Shell

      </div>

      docker run --name dbdata ubuntu echo "Data container."
      </div>

      在需要使用這個數據容器的容器創建時–volumes-from [容器名]的方式來使用這個數據共享容器。

      網絡

      Docker容器內的系統工作起來就像是一個虛擬機,容器內開放的端口并不會真正開放在主機上。可以使我們的容器更加安全,而且不會產生容器間端口的爭用。想要將Docker容器的端口開放到主機上,可以使用類似端口映射的方式。

      在Docker容器創建時,通過指定-p參數可以暴露容器的端口在主機上:

      Shell

      </div>

      docker run -it -p 22 ubuntu sh -c '/bin/bash'
      </div>

      現在我們就將容器的22端口開放在了主機上,注意主機上對應端口是自動分配的。如果想要指定某個端口,可以通過-p [主機端口]:[容器端口]參數指定。

      容器和容器之間想要網絡通訊,可以直接使用–link參數將兩個容器連接起來。例如WordPress容器對some-mysql的連接:

      Shell

      </div>

      docker run --name some-wordpress --link some-mysql:mysql -p 8080:80 -d wordpress
      </div>

      環境變量

      通過Docker打包的應用,對外就像是一個密閉的exe可執行文件。有時候我們希望Docker能夠使用一些外部的參數來使用容器,這時候參數可以通過環境變量傳遞進去,通常情況下用來傳遞比如MySQL數據庫連接這種的東西。環境變量通過-e參數向容器傳遞:

      Shell

      </div>

      docker run --name some-wordpress -e WORDPRESS_DB_HOST=10.1.2.3:3306 \ -e WORDPRESS_DB_USER=... -e WORDPRESS_DB_PASSWORD=... -d wordpress
      </div>

      關于Docker到現在就有了一個基本的認識了。接下來我會給大家介紹如何創建鏡像,以及如何利用公有云直接發布的基于Docker的應用。

      創建鏡像

      Docker強大的威力在于可以把自己開發的應用隨同各種依賴環境一起打包、分發、運行。要創建一個新的Docker鏡像,通常基于一個已有的Docker鏡像來創建。Docker提供了兩種方式來創建鏡像:把容器創建為一個新的鏡像、使用Dockerfile創建鏡像。

      將容器創建為鏡像

      為了創建一個新的鏡像,我們先創建一個新的容器作為基底:

      Shell

      </div>

      docker run -it ubuntu:latest sh -c '/bin/bash'
      </div>

      現在我們可以對這個容器進行修改了,例如我們可以配置PHP環境、將我們的項目代碼部署在里面等:

      Shell

      </div>

      apt-get install php # some other opreations ...
      </div>

      當執行完操作之后,我們按Ctrl+D退出容器,接下來使用docker ps -a來查找我們剛剛創建的容器ID:

      Shell

      </div>

      docker ps -a
      </div>

      可以看到我們最后操作的那個ubuntu容器。這時候只需要使用docker commit即可把這個容器變為一個鏡像了:

      Shell

      </div>

      docker commit 8d93082a9ce1 ubuntu:myubuntu
      </div>

      這時候docker容器會被創建為一個新的Ubuntu鏡像,版本名稱為myubuntu。以后我們可以隨時使用這個鏡像來創建容器了,新的容器將自動包含上面對容器的操作。

      如果我們要在另外一臺機器上使用這個鏡像,可以將一個鏡像導出:

      Shell

      </div>

      docker save -o myubuntu.tar.gz ubuntu:myubuntu
      </div>

      現在我們可以把剛才創建的鏡像打包為一個文件分發和遷移了。要在一臺機器上導入鏡像,只需要:

      docker import myubuntu.tar.gz

      這樣在新機器上就擁有了這個鏡像。

      注意:通過導入導出的方式分發鏡像并不是Docker的最佳實踐,因為我們有Docker Hub。

      Docker Hub提供了類似GitHub的鏡像存管服務。一個鏡像發布到Docker Hub不僅可以供更多人使用,而且便于鏡像的版本管理。關于Docker Hub的使用,之后我會單獨寫一篇文章展開介紹。另外,在一個企業內部可以通過自建 Docker Registry 的方式來統一管理和發布鏡像。將Docker Registry集成到版本管理和上線發布的工作流之中,還有許多工作要做,在我整理出最佳實踐后會第一時間分享。

      使用Dockerfile創建鏡像

      使用命令行的方式創建Docker鏡像通常難以自動化操作。在更多的時候,我們使用Dockerfile來創建Docker鏡像。 Dockerfile是一個純文本文件,它記載了從一個鏡像創建另一個新鏡像的步驟。撰寫好Dockerfile文件之后,我們就可以輕而易舉的使用 docker build命令來創建鏡像了。

      Dockerfile非常簡單,僅有以下命令在Dockerfile中常被使用:

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr>

      </tr> </tbody> </table>

      下面是一個Dockerfile的例子:

      # This is a comment FROM ubuntu:14.04 MAINTAINER Kate Smith <ksmith@example.com>
      RUN apt-get update && apt-get install -y ruby ruby-dev
      RUN gem install sinatra

      這里其他命令都比較好理解,唯獨CMD和ENTRYPOINT我需要特殊說明一下。CMD命令可用指定Docker容器啟動時默認的命令,例如我們上面例 子提到的docker run -it ubuntu:latest sh -c ‘/bin/bash’。其中sh -c ‘/bin/bash’就是通過手工指定傳入的CMD。如果我們不加這個參數,那么容器將會默認使用CMD指定的命令啟動。ENTRYPOINT是什么 呢?從字面看是進入點。沒錯,它就是進入點。 ENTRYPOINT用來指定特定的可執行文件、Shell腳本,并把啟動參數或CMD指定的默認值,當作附加參數傳遞給ENTRYPOINT。

      不好理解是吧?我們舉一個例子:

      ENTRYPOINT ['/usr/bin/mysql'] CMD ['-h 192.168.100.128', '-p']

      假設這個鏡像內已經準備好了mysql-client,那么通過這個鏡像,不加任何額外參數啟動容器,將會給我們一個mysql的控制臺,默認連 接到192.168.100.128這個主機。然而我們也可以通過指定參數,來連接別的主機。但是不管無論如何,我們都無法啟動一個除了mysql客戶端 以外的程序。因為這個容器的ENTRYPOINT就限定了我們只能在mysql這個客戶端內做事情。這下是不是明白了~

      因此,我們在使用Dockerfile創建文件的時候,可以創建一個entrypoint.sh腳本,作為系統入口。在這個文件里面,我們可以進 行一些基礎性的自舉操作,比如檢查環境變量,根據需要初始化數據庫等等。下面兩個文件是我在SimpleOA項目中添加的Dockerfile和 entrypoint.sh,僅供參考:

      https://github.com/starlight36/SimpleOA/blob/master/Dockerfile

      https://github.com/starlight36/SimpleOA/blob/master/docker-entrypoint.sh </div>

      在準備好Dockerfile之后,我們就可以創建鏡像了:

      Shell

      </div>

      docker build -t starlight36/simpleoa .
      </div>

      關于Dockerfile的更詳細說明,請參考 https://docs.docker.com/reference/builder/

      雜項和最佳實踐

      在產品構建的生命周期里使用Docker, 最佳實踐是把Docker集成到現有的構建發布流程里面。 這個過程并不復雜,可以在持續集成系統構建測試完成后,將打包的步驟改為docker build,持續集成服務將會自動將構建相應的Docker鏡像。打包完成后,可以由持續集成系統自動將鏡像推送到Docker Registry中。生產服務器可以直接Pull最新版本的鏡像,更新容器即可很快地實現更新上線。目前Atlassian Bamboo已經支持Docker的構建了。

      由于Docker使用聯合文件系統,所以并不用擔心多次發布的版本會占用更多的磁盤資源,相同的鏡像只存儲一份。所以 最佳實踐是在不同層次上構建Docker鏡像。 比如應用服務器依賴于PHP+Nginx環境,那么可以把定制好的這個PHP環境作為一個鏡像,應用服務器從這個鏡像構建鏡像。這樣做的好處是,如果PHP環境要升級,更新了這個鏡像后,重新構建應用鏡像即可完成升級,而不需要每個應用項目分別升級PHP環境。

      新手經常會有疑問的是關于Docker打包的粒度,比如MySQL要不要放在鏡像中? 最佳實踐是根據應用的規模和可預見的擴展性來確定Docker打包的粒度。 例如某小型項目管理系統使用LAMP環境,由于團隊規模和使用人數并不會有太大的變化(可預計的團隊規模范圍是幾人到幾千人),數據庫也不會承受無法承載 的記錄數(生命周期內可能一個表最多會有數十萬條記錄),并且客戶最關心的是快速部署使用。那么這時候把MySQL作為依賴放在鏡像里是一種不錯的選擇。 當然如果你在為一個互聯網產品打包,那最好就是把MySQL獨立出來,因為MySQL很可能會單獨做優化做集群等。

      使用公有云構建發布運行Docker也是個不錯的選擇。 國內 DaoCloud 提供了從構建到發布到運行的全生命周期服務。 特別適合像微擎這種微信公眾平臺、或者中小型企業CRM系統。上線周期更短,比使用IAAS、PAAS的云服務更具有優勢。

      參考資料:

      深入理解Docker Volume

      http://dockone.io/article/128

      WordPress  https://registry.hub.docker.com/_/wordpress/

      Docker學習—鏡像導出 http://www.sxt.cn/u/756/blog/5339

      Dockerfile Reference

      https://docs.docker.com/reference/builder/

      關于Dockerfile  http://blog.tankywoo.com/docker/2014/05/08/docker-2-dockerfile.html

       本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
       轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
       本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
      命令 參數 說明
      # 注釋說明
      FROM <image>[:<tag>] 從一個已有鏡像創建,例如ubuntu:latest
      MAINTAINER Author <some-one@example.com> 鏡像作者名字,如Max Liu <some-one@example.com>
      RUN <cmd>或者[‘cmd1’, ‘cmd2’…] 在鏡像創建用的臨時容器里執行單行命令
      ADD <src> <dest> 將本地的<src>添加到鏡像容器中的<dest>位置
      VOLUME <path>或者[‘/var’, ‘home’] 將指定的路徑掛載為數據卷
      EXPOSE <port> [<port>…] 將指定的端口暴露給主機
      ENV <key> <value> 或者 <key> = <value> 指定環境變量值
      CMD [“executable”,”param1″,”param2″] 容器啟動時默認執行的命令。注意一個Dockerfile中只有最后一個CMD生效。
      ENTRYPOINT [“executable”, “param1″, “param2″] 容器的進入點。
    • sesese色