帶你了從零瞭解Docker
2013年釋出至今, Docker 是近年來非常火的容器技術, 一直廣受矚目,被認為可能會改變軟體行業。而且啊 Docker不僅僅是linux Redhat 和Canonical等Linux巨頭眼裡的寵兒,微軟等專有軟體公司也在熱烈擁抱 Docker,所以就知道 Docker 為啥這麼火了。
我相信有很多人對 Docker 感興趣,都想學學 Docker,畢竟天天聽、畢竟這麼火、畢竟技多不壓身。許多人並不清楚 Docker 到底是什麼,要解決什麼問題,好處又在哪裡?接下來我就詳細解釋一下,幫助大家理解它,還帶有簡單易懂的例項,教你如何將它用於日常開發。
什麼是容器
一句話概括容器:容器就是將軟體打包成標準化單元,以用於開發、交付和部署。
- 容器映象是輕量的,可執行的獨立軟體包,包含軟體執行所需的所有內容:程式碼,執行時環境,系統工具,系統庫和設定。
- 容器化軟體適用於基於Linux適用於基於Linux和Windows的應用,在任何環境中都能夠始終如一地執行。
- 容器賦予了軟體獨立性,使其免受外在環境差異(例如,開發和預演環境的差異)的影響,從而有助於減少團隊間在相同基礎設施上執行不同軟體時的衝突。
我覺得容器就是一個存放東西的地方,就像房子可以裝各種傢俱,暑假可以放各種書。我們現在所說的容器存放的東西可能更偏向於應用比如網站,程式甚至是系統環境。
虛擬機器和容器
虛擬機器
虛擬機器就是帶環境安裝的一種解決方案,他可以再一種作業系統裡面執行另一種作業系統,比如在Windows系統裡面執行Linux系統,應用程式對此毫無感知,因為虛擬機器看上去跟真是系統一模一樣,而對於底層系統來說,虛擬機器就是一個普通檔案,不需要了就刪掉,對其他部分毫無影響。
雖然使用者可以通過虛擬機器還原團建的原始環境。但是如下缺點。
(1)資源佔用多
虛擬機器會獨佔一部分記憶體和硬碟空間。他執行的時候,其他程式就不能使用這些資源了。哪怕虛擬機器裡面的應用程式,真正使用的記憶體只有1MB,虛擬機器卻需要幾百MB的記憶體才能執行。一個系統一般只支援幾十個虛擬機器。
(2)冗餘步驟多
虛擬機器是完整的作業系統,一些系統級別的操作步驟,往往無法跳過,比如使用者登陸。
(3)啟動慢
啟動系統需要多久,啟動虛擬機器就需要多久。可能要等幾分鐘,應用程式才能真正執行。
Linux容器
由於虛擬機器存在這些缺點,Linux發展出了另一種虛擬化技術,Linux容器。
Linux容器不是模擬一個完整的作業系統,而是對程式進行隔離。或者說,在正常程序的外面套了一個保護層。對於容器裡面的程序來說,它接觸到的各種資源都是虛擬的,從而實現與底層系統的隔離。
由於容器是程序級別的,相比虛擬機器有很多優勢。
(1)啟動快
容器裡面的應用,直接就是底層系統的一個程序,而不是虛擬機器內部的程序。所以,啟動容器相當於啟動本機的一個程序,而不是啟動一個作業系統,速度就快很多。
(2)資源佔用少
容器只佔用需要的資源,不佔用那些沒有用到的資源;虛擬機器由於是完整的作業系統,不可避免要佔用所有資源。另外,多個容器可以共享資源,虛擬機器都是獨享資源。一個單機上支援上千個容器。
(3)體積小
容器只要包含用到的元件即可,而虛擬機器是整個作業系統的打包,所以容器檔案比虛擬機器檔案要小很多。
兩者對比
傳統虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統,在該系統上再執行所需應用程序,容器虛擬化的是作業系統而不是硬體,容器之間是共享同一套作業系統資源的。虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統。因此容器的隔離級別會稍低一些。
簡單來說,容器和虛擬機器具有相似的資源隔離和分配優勢,但功能有所不同,因為容器虛擬化的是作業系統,而不是硬體,因此容器更容易移植,效率也更高。而容器的應用程序直接運行於宿主的核心,容器內沒有自己的核心,而且也沒有進行硬體虛擬。因此容器要比傳統虛擬機器更輕便。
容器是一個應用層抽象,用於將程式碼和依賴資源打包在一起。多個容器可以在同一臺機器上執行,共享作業系統核心,但各自作為獨立的程序在使用者空間中執行。與虛擬機器相比,容器佔用的空間交少,瞬間就能完成啟動。
虛擬機器是一個物理硬體層抽象,用於將一臺伺服器變成多臺伺服器。管理程式允許多個vm在一臺機器上執行。每個vm都包含一整套作業系統,一個或多個應用,必要的二進位制檔案和庫資源,因此佔用大量空間。而vm啟動也非常緩慢。
什麼是Docker
Docker是屬於Linux容器的一種封裝,提供簡單易用的容器使用介面,他是目前最流行的Linux容器解決方案。
Docker 將應用程式與該程式的依賴,打包在一個檔案裡。執行這個檔案,就會生成一個虛擬容器。程式在這個虛擬容器裡執行,就好像在真實的物理機上執行一樣。有了Docker,就不用擔心環境問題。
總體來說,Docker 的介面相當簡單,使用者可以方便地建立和使用容器,把自己的應用放入容器。容器還可以進行版本管理、複製、分享、修改,就像管理普通的程式碼一樣。
Docker基本概念
Docker 中有三個核心概念:Image、Container、Repository。
- 映象(Image)
- 容器(Container)
- 倉庫(Repository)
理解了這三個概念,就理解了 Docker 的整個生命週期,
映象(Image)一個特殊的檔案系統
作業系統分為核心和使用者空間。對於Linux而言,核心啟動後,會掛載root檔案系統為其提供使用者空間支援。而Docker映象(Image),就相當於一個root檔案系統。
Docker 映象是一個特殊的檔案系統,除了提供容器執行時所需的程式、庫、資源、配置等檔案外,還包含了一些為執行時準備的一些配置引數(如匿名卷、環境變數、使用者等)。 映象不包含任何動態資料,其內容在構建之後也不會被改變。
映象構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。比如,刪除前一層檔案的操作,實際不是真的刪除前一層的檔案,而是僅在當前層標記為該檔案已刪除。在最終容器執行的時候,雖然不會看到這個檔案,但是實際上該檔案會一直跟隨映象。因此,在構建映象的時候,需要額外小心,每一層儘量只包含該層需要新增的東西,任何額外的東西應該在該層構建結束前清理掉。
分層儲存的特徵還使得映象的複用、定製變的更為容易。甚至可以用之前構建好的映象作為基礎層,然後進一步新增新的層,以定製自己所需的內容,構建新的映象。
和windows的那種iso映象相比,Docker中的映象的概念不會陌生。但是windows的那種iso映象相比,Docker中的映象是分層的,可複用的,而非簡單的一堆檔案碟在一起(類似於一個壓縮包的原始碼和一個git倉庫的區別)
容器(Container)
—映象執行時的實體
映象(Image)和容器(Container)的關係,就像是面向物件程式設計中的 類 和 例項 一樣,映象是靜態的定義,容器是映象執行時的實體。容器可以被建立、啟動、停止、刪除、 暫停等。
容器的實質是程序,但與直接在宿主執行的程序不同,容器程序運行於屬於自己的獨立的 名稱空間。前面講過映象使用的是分層儲存,容器也是如此。
容器儲存層的生存週期和容器一樣,容器消亡時,容器儲存層也隨之消亡。因此,任何保存於容器儲存層的資訊都會隨容器刪除而丟失。
容器的存在離不開映象的支援,他是映象執行時的一個載體(類似於例項和類的關係)。依託Docker的虛擬化技術,給容器建立了獨立的埠,程序,檔案等空間,Container就是一個宿機隔離“容器”。容器可宿主機之間可以進行port,volumes,network等通訊。
倉庫(Repository)——集中存放映象檔案的地方
映象構建完成後,可以很容易的在當前宿主上執行,但是,如果需要在其它伺服器上使用這個映象,我們就需要一個集中的儲存、分發映象的服務,Docker Registry就是這樣的服務。
一個 Docker Registry中可以包含多個倉庫(Repository);每個倉庫可以包含多個標籤(Tag);每個標籤對應一個映象。所以說:映象倉庫是Docker用來集中存放映象檔案的地方類似於我們之前常用的程式碼倉庫。
通常,一個倉庫會包含同一個軟體不同版本的映象
,而標籤就常用於對應該軟體的各個版本
。我們可以通過<倉庫名>:<標籤>
的格式來指定具體是這個軟體哪個版本的映象。如果不給出標籤,將以 latest 作為預設標籤.。
Docker 作用
1.多環境的部署切換
業務中王灣需要區分開發環境與線上環境,利用Docker能原封不動的將開發環境中的程式碼與環境原封不動無汙染的遷移到線上環境,配合一定的自動胡流程即可自哦對那個發動。
2.複雜環境一鍵配置
某些場景下可能會配一些超級複雜的環境,這個時候可以對Docker對環境配置做封裝,直接生成映象,讓大家低成本使用。
3.持續整合單元測試
類似於 travis-ci 這種
4.同應用多版本隔離,檔案隔離
比如這個專案依賴java 7 ,那個專案依賴java 8,同一個伺服器上跑了100個陳永,可以用Docker建立隔離開,防止互相傳染。
5.雲構建
同一個倉庫下不同人開發往往會遇到不同的人使用不同的包版本 且自己根本不知道與別人不一樣,最終導致釋出之後產生線上問題。利用 Docker 可以在雲端新建容器,遠端無汙染、低成本 構建程式碼,實現不同人用的一定是同一個版本 。
6.省錢
低成本安全超售
相關命令
安裝
Docker 的安裝是非常便捷的,在 macOS、ubuntu 等下面都有一鍵式安裝工具或者指令碼。更多可以參考Docker 官方教程。
下面簡單介紹一下ubuntu下的安裝。
Docker 支援以下的 Ubuntu 版本:
- Ubuntu Precise 12.04 (LTS)
- Ubuntu Trusty 14.04 (LTS)
- Ubuntu Wily 15.10
Docker 要求 Ubuntu 系統的核心版本高於 3.10 ,檢視本頁面的前提條件來驗證你的 Ubuntu 版本是否支援 Docker。
通過 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 REPOSITORYTAGIMAGE IDCREATEDSIZE ubuntu14.0490d5884b1ee05 days ago188 MB php5.6f40e9e0f10c89 days ago444.8 MB nginxlatest6f8d099c3adc12 days ago182.7 MB mysql5.6f2e8d6c772c03 weeks ago324.6 MB httpdlatest02ef73cf1bc03 weeks ago194.4 MB ubuntu15.104e3b13c8a2664 weeks ago136.3 MB hello-worldlatest690ed74de00f6 months ago960 B training/webapplatest6fae60ef344611 months ago348.8 MB複製程式碼
各個選項說明:
-
REPOSITORY: 表示映象的倉庫源
-
TAG: 映象的標籤
-
IMAGE ID: 映象ID
-
CREATED: 映象建立時間
-
SIZE: 映象大小
建立Docker容器
docker create 命令通過映象去建立一個容器,同時吐出容器 id。
> docker create --name ubuntuContainer ubuntu:18.04 0da83bc6515ea1df100c32cccaddc070199b72263663437b8fe424aadccf4778 複製程式碼複製程式碼
用docker start 即可執行改容器。
> docker start ubuntuContainer 複製程式碼複製程式碼
用docker ps 即可檢視執行中的 container
> docker ps CONTAINER IDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 9298a27262daubuntu:18.04"/bin/bash"4 minutes agoUp About a minuteubuntuContainer 複製程式碼複製程式碼
用docker exec 即可進入該 container。
> docker exec -it 9298 root@9298a27262da:/# ls binbootdevetchomeliblib64mediamntoptprocrootrunsbinsrvsystmpusrvar root@9298a27262da:/# exit 複製程式碼複製程式碼
用docker run 可以一步到位建立並執行一個容器,然後進入該容器。
> docker run -it --name runUbuntuContainer ubuntu:18.04 /bin/bash root@57cdd61d4383:/# ls binbootdevetchomeliblib64mediamntoptprocrootrunsbinsrvsystmpusrvar root@57cdd61d4383:/# # docker ps 可以查到已經成功運行了 runUbuntuContainer > docker ps CONTAINER IDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 57cdd61d4383ubuntu:18.04"/bin/bash"9 seconds agoUp 8 secondsrunUbuntuContainer 9298a27262daubuntu:18.04"/bin/bash"9 minutes agoUp 6 minutes 複製程式碼
commit 容器,建立新映象
和 Ghost 裝 windows 一樣,很多時候,我們期望能定製自己的映象,在裡面安裝一些基礎環境(比如上文中的 node),然後製作出自己要的基礎映象。這個時候docker commit 就派上用場了。
> docker commit --author "rccoder" --message "curl+node" 9298 rccoder/myworkspace:v1 sha256:68e83119eefa0bfdc8e523ab4d16c8cf76770dbb08bad1e32af1c872735e6f71 # 通過 docker images 就能看到新制作的 rccoder/myworkspace 就躺在這裡了 >docker images REPOSITORYTAGIMAGE IDCREATEDSIZE rccoder/myworkspacev1e0d73563fae820 seconds ago196MB 複製程式碼複製程式碼
接著,試一下我們新建立的映象?
> docker run -it --name newWorkSpace rccoder/myworkspace:v1 /bin/bash root@9109f6985735:/# node -v 8.0.0 複製程式碼複製程式碼
看起來沒問題。
push 映象到 docker hub
映象製作好了,怎麼共享出去讓別人使用呢?這裡以 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複製程式碼
Dockerfile
用 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 daemon3.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 abinbootdevetchomeliblib64mediamntoptprocrootrunsbinsrvsystmpusrvar 複製程式碼複製程式碼
藉助 Dockerfile 的能力,Docker 留下了無限的可能。
在容器裡安裝 Mysql 環境
方法一、docker pull php
查詢Docker Hub上的php映象
runoob@runoob:~/php-fpm$ docker search php NAMEDESCRIPTIONSTARSOFFICIALAUTOMATED phpWhile designed for web development, the PH...1232[OK] richarvey/nginx-php-fpmContainer running Nginx + PHP-FPM capable ...207[OK] phpmyadmin/phpmyadminA web interface for SQL/">MySQL and MariaDB.123[OK] eboraas/apache-phpPHP5 on Apache (with SSL support), built o...69[OK] php-zendserverZend Server - the integrated PHP applicati...69[OK] million12/nginx-phpNginx + PHP-FPM 5.5, 5.6, 7.0 (NG), CentOS...67[OK] webdevops/php-nginxNginx with PHP-FPM39[OK] webdevops/php-apacheApache with PHP-FPM (based on webdevops/php)14[OK] phpunit/phpunitPHPUnit is a programmer-oriented testing f...14[OK] tetraweb/phpPHP 5.3, 5.4, 5.5, 5.6, 7.0 for CI and run...12[OK] webdevops/phpPHP (FPM and CLI) service container10[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 REPOSITORYTAGIMAGE IDCREATEDSIZE php5.6-fpm025041cd3aa56 days ago456.3 MB複製程式碼
方法二、通過 Dockerfile 構建
建立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 REPOSITORYTAGIMAGE IDCREATEDSIZE php5.6-fpm025041cd3aa56 days ago456.3 MB複製程式碼