2013年發佈至今, Docker 是近年來很是火的容器技術, 一直廣受矚目,被認爲可能會改變軟件行業。並且啊 Docker不只僅是linux Redhat 和Canonical等Linux巨頭眼裏的寵兒,微軟等專有軟件公司也在熱烈擁抱 Docker,因此就知道 Docker 爲啥這麼火了。php
我相信有不少人對 Docker 感興趣,都想學學 Docker,畢竟每天聽、畢竟這麼火、畢竟技多不壓身。許多人並不清楚 Docker 究竟是什麼,要解決什麼問題,好處又在哪裏?接下來我就詳細解釋一下,幫助你們理解它,還帶有簡單易懂的實例,教你如何將它用於平常開發。java
一句話歸納容器:容器就是將軟件打包成標準化單元,以用於開發、交付和部署。node
我以爲容器就是一個存放東西的地方,就像房子能夠裝各類傢俱,暑假能夠放各類書。咱們如今所說的容器存放的東西可能更偏向於應用好比網站,程序甚至是系統環境。mysql
虛擬機就是帶環境安裝的一種解決方案,他能夠再一種操做系統裏面運行另外一種操做系統,好比在Windows系統裏面運行Linux系統,應用程序對此毫無感知,由於虛擬機看上去跟真是系統如出一轍,而對於底層系統來講,虛擬機就是一個普通文件,不須要了就刪掉,對其餘部分毫無影響。linux
雖然用戶能夠經過虛擬機還原團建的原始環境。可是以下缺點。nginx
(1)資源佔用多git
虛擬機會獨佔一部份內存和硬盤空間。他運行的時候,其餘程序就不能使用這些資源了。哪怕虛擬機裏面的應用程序,真正使用的內存只有1MB,虛擬機卻須要幾百MB的內存才能運行。一個系統通常只支持幾十個虛擬機。web
(2)冗餘步驟多sql
虛擬機是完整的操做系統,一些系統級別的操做步驟,每每沒法跳過,好比用戶登錄。docker
(3)啓動慢
啓動系統須要多久,啓動虛擬機就須要多久。可能要等幾分鐘,應用程序才能真正運行。
因爲虛擬機存在這些缺點,Linux發展出了另外一種虛擬化技術,Linux容器。
Linux容器不是模擬一個完整的操做系統,而是對程序進行隔離。或者說,在正常進程的外面套了一個保護層。對於容器裏面的進程來講,它接觸到的各類資源都是虛擬的,從而實現與底層系統的隔離。
因爲容器是進程級別的,相比虛擬機有不少優點。
(1)啓動快
容器裏面的應用,直接就是底層系統的一個進程,而不是虛擬機內部的進程。因此,啓動容器至關於啓動本機的一個進程,而不是啓動一個操做系統,速度就快不少。
(2)資源佔用少
容器只佔用須要的資源,不佔用那些沒有用到的資源;虛擬機因爲是完整的操做系統,不可避免要佔用全部資源。另外,多個容器能夠共享資源,虛擬機都是獨享資源。一個單機上支持上千個容器。
(3)體積小
容器只要包含用到的組件便可,而虛擬機是整個操做系統的打包,因此容器文件比虛擬機文件要小不少。
傳統虛擬機技術是虛擬出一套硬件後,在其上運行一個完整操做系統,在該系統上再運行所需應用進程,容器虛擬化的是操做系統而不是硬件,容器之間是共享同一套操做系統資源的。虛擬機技術是虛擬出一套硬件後,在其上運行一個完整操做系統。所以容器的隔離級別會稍低一些。
簡單來講,容器和虛擬機具備類似的資源隔離和分配優點,但功能有所不一樣,由於容器虛擬化的是操做系統,而不是硬件,所以容器更容易移植,效率也更高。而容器的應用進程直接運行於宿主的內核,容器內沒有本身的內核,並且也沒有進行硬件虛擬。所以容器要比傳統虛擬機更輕便。
容器是一個應用層抽象,用於將代碼和依賴資源打包在一塊兒。多個容器能夠在同一臺機器上運行,共享操做系統內核,但各自做爲獨立的進程在用戶空間中運行。與虛擬機相比,容器佔用的空間交少,瞬間就能完成啓動。
虛擬機是一個物理硬件層抽象,用於將一臺服務器變成多臺服務器。管理程序容許多個vm在一臺機器上運行。每一個vm都包含一整套操做系統,一個或多個應用,必要的二進制文件和庫資源,所以佔用大量空間。而vm啓動也很是緩慢。
Docker是屬於Linux容器的一種封裝,提供簡單易用的容器使用接口,他是目前最流行的Linux容器解決方案。
Docker 將應用程序與該程序的依賴,打包在一個文件裏。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裏運行,就好像在真實的物理機上運行同樣。有了Docker,就不用擔憂環境問題。
整體來講,Docker 的接口至關簡單,用戶能夠方便地建立和使用容器,把本身的應用放入容器。容器還能夠進行版本管理、複製、分享、修改,就像管理普通的代碼同樣。
理解了這三個概念,就理解了 Docker 的整個生命週期,
操做系統分爲內核和用戶空間。對於Linux而言,內核啓動後,會掛載root文件系統爲其提供用戶空間支持。而Docker鏡像(Image),就至關於一個root文件系統。
Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。 鏡像不包含任何動態數據,其內容在構建以後也不會被改變。
鏡像構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在本身這一層。好比,刪除前一層文件的操做,實際不是真的刪除前一層的文件,而是僅在當前層標記爲該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,可是實際上該文件會一直跟隨鏡像。所以,在構建鏡像的時候,須要額外當心,每一層儘可能只包含該層須要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
分層存儲的特徵還使得鏡像的複用、定製變的更爲容易。甚至能夠用以前構建好的鏡像做爲基礎層,而後進一步添加新的層,以定製本身所需的內容,構建新的鏡像。
和windows的那種iso鏡像相比,Docker中的鏡像的概念不會陌生。可是windows的那種iso鏡像相比,Docker中的鏡像是分層的,可複用的,而非簡單的一堆文件碟在一塊兒(相似於一個壓縮包的源碼和一個git倉庫的區別)
容器的實質是進程,但與直接在宿主執行的進程不一樣,容器進程運行於屬於本身的獨立的 命名空間。前面講過鏡像使用的是分層存儲,容器也是如此。
容器存儲層的生存週期和容器同樣,容器消亡時,容器存儲層也隨之消亡。所以,任何保存於容器存儲層的信息都會隨容器刪除而丟失。
容器的存在離不開鏡像的支持,他是鏡像運行時的一個載體(相似於實例和類的關係)。依託Docker的虛擬化技術,給容器建立了獨立的端口,進程,文件等空間,Container就是一個宿機隔離「容器」。容器可宿主機之間能夠進行port,volumes,network等通訊。
鏡像構建完成後,能夠很容易的在當前宿主上運行,可是, 若是須要在其它服務器上使用這個鏡像,咱們就須要一個集中的存儲、分發鏡像的服務,Docker Registry就是這樣的服務。
一個 Docker Registry中能夠包含多個倉庫(Repository);每一個倉庫能夠包含多個標籤(Tag);每一個標籤對應一個鏡像。因此說:鏡像倉庫是Docker用來集中存放鏡像文件的地方相似於咱們以前經常使用的代碼倉庫。
一般,一個倉庫會包含同一個軟件不一樣版本的鏡像,而標籤就經常使用於對應該軟件的各個版本 。咱們能夠經過<倉庫名>:<標籤>
的格式來指定具體是這個軟件哪一個版本的鏡像。若是不給出標籤,將以 latest 做爲默認標籤.。
業務中王灣須要區分開發環境與線上環境,利用Docker能原封不動的將開發環境中的代碼與環境原封不動無污染的遷移到線上環境,配合必定的自動胡流程便可自哦對那個發動。
某些場景下可能會配一些超級複雜的環境,這個時候能夠對Docker對環境配置作封裝,直接生成鏡像,讓你們低成本使用。
相似於 travis-ci 這種
好比這個項目依賴java 7 ,那個項目依賴java 8,同一個服務器上跑了100個陳永,能夠用Docker創建隔離開,防止互相傳染。
同一個倉庫下不一樣人開發每每會遇到不一樣的人使用不一樣的 包版本且本身根本不知道與別人不同,最終致使發佈以後產生線上問題。利用 Docker 能夠在雲端新建容器,遠程 無污染、低成本 構建代碼,實現 不一樣人用的必定是同一個版本。
低成本安全超售
Docker 的安裝是很是便捷的,在 macOS、ubuntu 等下面都有一鍵式安裝工具或者腳本。更多能夠參考 Docker 官方教程。
下面簡單介紹一下ubuntu下的安裝。
Docker 支持如下的 Ubuntu 版本:
經過 uname -r 命令查看你當前的內核版本
runoob@runoob:~$ uname -r
1.選擇國內的雲服務商,這裏選擇阿里云爲例
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -複製代碼
2.安裝所須要的包
sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual複製代碼
3.添加使用 HTTPS 傳輸的軟件包以及 CA 證書
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates複製代碼
4.添加GPG密鑰
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D複製代碼
5.添加軟件源
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list複製代碼
6.添加成功後更新軟件包緩存
sudo apt-get update複製代碼
7.安裝docker
sudo apt-get install docker-engine複製代碼
8.啓動 docker
sudo systemctl enable docker
sudo systemctl start docker複製代碼
DockerHub 等網站都提供了衆多鏡像,通常狀況下咱們都會從它那找個鏡像做爲基礎鏡像,而後再進行咱們的後續操做。
當咱們在本地主機上使用一個不存在的鏡像時 Docker 就會自動下載這個鏡像。若是咱們想預先下載這個鏡像,咱們可使用 docker pull 命令來下載它。
利用docker pull 命令便可從相關 hub 網站上拉取鏡像到本地。同時在拉的過程當中就能看到是按照多個 「層」 去拉鏡像的
Crunoob@runoob:~$ docker pull ubuntu:13.10
13.10: Pulling from library/ubuntu
6599cadaf950: Pull complete
23eda618d451: Pull complete
f0be3084efe9: Pull complete
52de432f084b: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:15b79a6654811c8d992ebacdfbd5152fcf3d165e374e264076aa435214a947a3
Status: Downloaded newer image for ubuntu:13.10複製代碼
咱們可使用 docker images 來列出本地主機上的鏡像。
runoob@runoob:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
nginx latest 6f8d099c3adc 12 days ago 182.7 MB
mysql 5.6 f2e8d6c772c0 3 weeks ago 324.6 MB
httpd latest 02ef73cf1bc0 3 weeks ago 194.4 MB
ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
hello-world latest 690ed74de00f 6 months ago 960 B
training/webapp latest 6fae60ef3446 11 months ago 348.8 MB複製代碼
各個選項說明:
REPOSITORY:表示鏡像的倉庫源
TAG:鏡像的標籤
IMAGE ID:鏡像ID
CREATED:鏡像建立時間
SIZE:鏡像大小
docker create 命令經過鏡像去建立一個容器,同時吐出容器 id。
> docker create --name ubuntuContainer ubuntu:18.04
0da83bc6515ea1df100c32cccaddc070199b72263663437b8fe424aadccf4778
複製代碼複製代碼
用 docker start 便可運行改容器。
> docker start ubuntuContainer
複製代碼複製代碼
用 docker ps 便可查看運行中的 container
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9298a27262da ubuntu:18.04 "/bin/bash" 4 minutes ago Up About a minute ubuntuContainer
複製代碼複製代碼
用 docker exec 便可進入該 container。
> docker exec -it 9298
root@9298a27262da:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@9298a27262da:/# exit
複製代碼複製代碼
用 docker run 能夠一步到位建立並運行一個容器,而後進入該容器。
> docker run -it --name runUbuntuContainer ubuntu:18.04 /bin/bash
root@57cdd61d4383:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@57cdd61d4383:/#
# docker ps 能夠查到已經成功運行了 runUbuntuContainer
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57cdd61d4383 ubuntu:18.04 "/bin/bash" 9 seconds ago Up 8 seconds runUbuntuContainer
9298a27262da ubuntu:18.04 "/bin/bash" 9 minutes ago Up 6 minutes 複製代碼
和 Ghost 裝 windows 同樣,不少時候,咱們指望能定製本身的鏡像,在裏面安裝一些基礎環境(好比上文中的 node),而後製做出本身要的基礎鏡像。這個時候 docker commit 就派上用場了。
> docker commit --author "rccoder" --message "curl+node" 9298 rccoder/myworkspace:v1
sha256:68e83119eefa0bfdc8e523ab4d16c8cf76770dbb08bad1e32af1c872735e6f71
# 經過 docker images 就能看到新制做的 rccoder/myworkspace 就躺在這裏了
>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rccoder/myworkspace v1 e0d73563fae8 20 seconds ago 196MB
複製代碼複製代碼
接着,試一下咱們新建立的鏡像?
> docker run -it --name newWorkSpace rccoder/myworkspace:v1 /bin/bash
root@9109f6985735:/# node -v
8.0.0
複製代碼複製代碼
看起來沒問題。
鏡像製做好了,怎麼共享出去讓別人使用呢?這裏以 push 到 docker hub 爲例。
第一步是先去 docker hub 註冊一個帳號,而後在終端上登陸帳號,進行 push。
> docker login
> docker push rccoder/myworkspace:v1
The push refers to repository [docker.io/rccoder/myworkspace]
c0913fec0e19: Pushing [=> ] 2.783MB/116.7MB
bb1eed35aacf: Mounted from library/ubuntu
5fc1dce434ba: Mounted from library/ubuntu
c4f90a44515b: Mounted from library/ubuntu
a792400561d8: Mounted from library/ubuntu
6a4e481d02df: Waiting複製代碼
用 Docker 進行持續集成?相比在瞭解 Docker 以前確定聽過這個事情,那就意外着須要從某個地方拷貝代碼,而後執行(對,聽上去有點 travis-ci 的那種感受)。
是時候該 Dockerfile 出場了!
Dockerfile 是一個由一堆命令+參數構成的腳本,使用 docker build 便可執行腳本構建鏡像,自動的去作一些事(同相似於travis-ci 中的 .travis.yml
)。
Dockerfile 的格式通通爲:
# Comment
INSTRUCTION arguments
複製代碼複製代碼
必須以 FROM BASE_IMAGE
開頭指定基礎鏡像。
更詳細的規範與說明請參考 Dockerfile reference。這裏咱們以基於上面的 rccoder/myworkspace:v1 做爲基礎鏡像,而後在根目錄建立 a 目錄爲例
Dockerfile 以下:
FROM rccoder/myworkspace:v1
RUN mkdir a
複製代碼複製代碼
而後執行:
> docker build -t newfiledocker:v1 .
Sending build context to Docker daemon 3.584kB
Step 1/2 : FROM rccoder/myworkspace:v1
---> 68e83119eefa
Step 2/2 : RUN mkdir a
---> Running in 1127aff5fbd3
Removing intermediate container 1127aff5fbd3
---> 25a8a5418af0
Successfully built 25a8a5418af0
Successfully tagged newfiledocker:v1
# 新建基於 newfiledocker 的容器並在終端中打開,發現裏面已經有 a 文件夾了。
> docker docker run -it newfiledocker:v1 /bin/bash
root@e3bd8ca19ffc:/# ls
a bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
複製代碼複製代碼
藉助 Dockerfile 的能力,Docker 留下了無限的可能。
查找Docker Hub上的php鏡像
runoob@runoob:~/php-fpm$ docker search php
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PH... 1232 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable ... 207 [OK]
phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 123 [OK]
eboraas/apache-php PHP5 on Apache (with SSL support), built o... 69 [OK]
php-zendserver Zend Server - the integrated PHP applicati... 69 [OK]
million12/nginx-php Nginx + PHP-FPM 5.5, 5.6, 7.0 (NG), CentOS... 67 [OK]
webdevops/php-nginx Nginx with PHP-FPM 39 [OK]
webdevops/php-apache Apache with PHP-FPM (based on webdevops/php) 14 [OK]
phpunit/phpunit PHPUnit is a programmer-oriented testing f... 14 [OK]
tetraweb/php PHP 5.3, 5.4, 5.5, 5.6, 7.0 for CI and run... 12 [OK]
webdevops/php PHP (FPM and CLI) service container 10 [OK]
...複製代碼
這裏咱們拉取官方的鏡像,標籤爲5.6-fpm
runoob@runoob:~/php-fpm$ docker pull php:5.6-fpm複製代碼
等待下載完成後,咱們就能夠在本地鏡像列表裏查到REPOSITORY爲php,標籤爲5.6-fpm的鏡像。
runoob@runoob:~/php-fpm$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB複製代碼
建立Dockerfile
首先,建立目錄php-fpm,用於存放後面的相關東西。
runoob@runoob:~$ mkdir -p ~/php-fpm/logs ~/php-fpm/conf複製代碼
logs目錄將映射爲php-fpm容器的日誌目錄
conf目錄裏的配置文件將映射爲php-fpm容器的配置文件
進入建立的php-fpm目錄,建立Dockerfile
經過Dockerfile建立一個鏡像,替換成你本身的名字
runoob@runoob:~/php-fpm$ docker build -t php:5.6-fpm .複製代碼
建立完成後,咱們能夠在本地的鏡像列表裏查找到剛剛建立的鏡像
runoob@runoob:~/php-fpm$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB複製代碼