docker 這麼火,我怎麼能不瞭解下?
從我聽到的關於 docker 的關鍵詞,諸如 容器
、go語言編寫
、虛擬化
、打包移植
等等,就覺得它是一個逼格有點高的東西。而且這玩意似乎不是給前端準備的,畢竟我們前端只是寫寫頁面( ̄∇ ̄),這東西太複雜了。
最後我當然還是去學習它,並慢慢嘗試用它。你要問原因,那就是真香。
本文涉及以下內容:
- Docker 用途理解
- Docker 安裝及加速器配置
- Docker 相關概念理解,以及學習相關命令,如映象命令和容器命令
- Docker 資料卷和資料卷容器
- Docker 安裝 nginx 實踐
理解 Docker 的用途
語言是蒼白的,但我還是想去說些什麼。如果去搜尋 docker 的定義,給出的答案就是一種容器引擎,開發者可以打包他們的應用以及依賴包到一個可移植的映象中,然後釋出到任何流行的 Linux或Windows 機器上。第一次看到這個解釋時我是似懂非懂的,我把容器理解為一個盒子,然後把程式碼打包到這個盒子裡,就可以移植到別處執行。作為頁面仔,我也不知道理解的對不對,而且沒弄懂這麼做的具體意義,這種操作給我的感覺就像是打包一個app,然後可以下載到別人手機上用。不知道是不是隻有我這麼認為。後來在看過很多關於 docker 的文章後,我才瞭解到 docker 的用途。
docker 可以解決軟體執行環境不一致所帶來的一系列問題。你是否聽過這樣一個靈魂質問:“我明明在本地執行地好好的,怎麼你線上就崩了???”
這是因為開發環境和生產環境基本不一樣,程式碼在哪執行,就要重新配置一套環境,這樣除了帶來時間成本外,一個大問題就是生產環境可能部署了不止一個專案,它們所依賴的環境版本不一樣。比如我本地用 nodejs 最新版本開發好了一個專案,想要部署到伺服器,但是伺服器上已經部署了一個 nodejs 專案,並且使用的是很久很久以前的一個版本,此時再直接部署新專案顯然就有很大的隱患了。雖然有其他辦法解決,但有了 docker 後,一切變的更優雅了。
囉嗦了這麼多,其實 docker 的作用就是把應用程式碼和所依賴的環境一起打包成一個檔案,執行這個檔案,會生成一個虛擬容器,程式碼在這個容器裡執行,就像在物理機上執行一樣,不受外界環境的影響。還有一個概念要了解一下,就是容器本身所處的環境,通常成為“宿主機”,這可以是一個 Linux 或 Windows 的機器。
總結成一句話就是:docker 是一種容器技術,主要解決程式碼跨環境遷移的問題。
安裝 Docker
安裝教程實在很多,我這裡演示的是在一臺 CentOS 7.5 64位 伺服器上的安裝,參考的 菜鳥教程。別的系統的安裝也可以自行檢視。
首先安裝所需的軟體包:
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
複製程式碼
使用以下命令來設定穩定的倉庫:
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
複製程式碼
安裝最新版本的 Docker Engine-Community 和 containerd:
sudo yum install docker-ce docker-ce-cli containerd.io
複製程式碼
安裝完成後輸入 docker version
驗證是否安裝成功。
配置映象加速器
跟 github 類似,docker也有一個映象儲存庫 DockerHub(關於映象,後面會說),由於國內網路原因,我們在拉取一些已有映象時會遇到困難,所以需要配置加速器。加速器有很多種,這裡推薦使用阿里雲的加速器,它是免費的,不需要購買任何東西。
登入阿里雲後搜尋關鍵詞 映象服務
,選擇容器映象服務:
第一次使用時,會讓你設定登入密碼,設定一下即可:
然後在左側選單點選映象加速器,右邊可以看到給你提供了一個加速地址,這個地址每個人的都不一樣。阿里雲很貼心地在下方給出直接執行的命令程式碼,選擇你的平臺,複製貼上所有程式碼,直接執行在終端即可:
執行結束後,可以使用命令 cat /etc/docker/daemon.json
檢視是否設定成功,結果如下:
{
"registry-mirrors": ["https://55zqg9lk.mirror.aliyuncs.com"]
}
複製程式碼
如果你想替換別的加速地址,直接修改後面的地址即可,修改完不要忘記執行:
sudo systemctl daemon-reload
sudo systemctl restart docker
複製程式碼
瞭解 Docker 的基礎概念
docker 有三個基本概念:
- 映象(Image):Docker 映象(Image),就相當於是一個 root 檔案系統。比如官方映象 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系統的 root 檔案系統。
- 容器(Container):映象(Image)和容器(Container)的關係,就像是物件導向程式設計中的類和例項一樣,映象是靜態的定義,容器是映象執行時的實體。容器可以被建立、啟動、停止、刪除、暫停等。
- 倉庫(Repository):倉庫可看著一個程式碼控制中心,用來儲存映象。
再說一下,映象
其實就是打包出來的包含程式碼和依賴環境的檔案,我們可以使用別人製作好的映象,也可以自己製作映象。而 容器
就是根據映象建立的,同一個映象可以建立很多容器,就像類
和物件
的關係。
另外,Docker 使用客戶端-伺服器 (C/S) 架構模式,使用遠端API來管理和建立Docker容器,可以用一張圖來了解:
我們先看 Hosts
,它是 Docker 主機,用於執行 Docker 守護程式和容器。它分為本地主機和遠端主機,主機下包含 daemon(守護程式)
,container(容器)
和 image(映象)
。daemon
是一個常駐在後臺的系統程式,當我們安裝完成 Docker 後,它就存在。
Registries
是倉庫,Docker 有一個官方的映象倉庫Docker Hub
,與github類似,我們可以獲取或上傳映象。我們也可以建立自己的私有映象庫。
Clients
是Docker客戶端,通過命令列與守護程式通訊。
Docker 相關命令
Docker 命令可以分三部分來說,即服務命令
,映象命令
和容器命令
。
服務命令
服務命令指的是操作 daemon 服務的命令,操控的是 docker 程式。它主要包含5個:
- 檢視 docker 狀態:
systemctl status docker
- 啟動 docker 服務:
systemctl start docker
- 停止 docker 服務:
systemctl stop docker
- 重啟 docker 服務:
systemctl restart docker
- 開機啟動 docker 服務:
systemctl enable docker
首先我們可以檢視一下當前 docker 服務狀態,使用 systemctl status docker
:
綠色部分的 active (running)
就表示 docker 正在執行,我們再來停止一次服務,並檢視狀態:
如圖,inactive (dead)
就表示 docker 服務已停止。再試下重啟服務:
開機啟動命令這裡就不演示了。
映象命令
映象命令用於操作映象(images)相關。
檢視映象
檢視本地所有映象,可使用命令:
docker images
複製程式碼
可以看到我的本地有一個 redis
的映象,這是因為我提前安裝了,如果沒安裝就是空的。顯示結果的第一行是表頭,分別表示為映象名稱
、版本號
、映象 id
、建立時間
和映象大小
。
檢視所有映象的 id,可以使用命令:
docker images -q
複製程式碼
我這裡只有一個映象,所以只顯示了一個 id,如果有多個映象的話會顯示所有的映象 id。
搜尋映象
有時候我們並不知道庫裡是否有我們需要的映象,這時候就需要先搜尋,使用命令:
docker search 映象名稱
複製程式碼
比如我們來搜尋 redis
:
如圖所示,會將所有 redis 相關源資訊列印出來,第一行依舊是頭,依次表示為:名稱
、描述
、star 數
、是否是官方出的
和 自動構建
。
拉取映象
拉取映象即從 docker 倉庫下載映象到本地,使用命令:
docker pull 映象名稱
複製程式碼
或者下載指定版本:
docker pull 映象名稱:版本號
複製程式碼
注意,當不指定版本號時,預設下載最新版本(latest版)。另外要指定下載某個版本時,可以去 DockerHub 檢視映象對應的一些版本號,不要隨便自定義版本號。下載就不演示了。
刪除映象
刪除指定映象,使用命令:
docker rmi 映象id
複製程式碼
注意這裡是要指定映象的 id ,而不是名稱。我們可以先使用 docker images
來檢視映象的id,然後再來刪除。刪除 redis
測試:
第一步檢視所有映象時,顯示有兩個映象,刪除 redis 後再檢視時只有一個了,說明刪除成功。
另外,當一次刪除多個映象時,可以將映象id依次輸入進去,這樣:
docker rmi id1 id2 id3...
複製程式碼
當要刪除所有的映象時,可以使用這樣一個組合命令:
docker rmi `docker images -q`
複製程式碼
這句命令的意思很明顯,就是將 docker images -q
查詢到的所有映象 id 傳給刪除命令,以達到刪除所有映象的效果。
容器命令
容器命令用於操控容器相關,是比較重要的部分,我們最終直接用於生產的也就是容器。
檢視容器
檢視本地所有正在執行中的容器,使用命令:
docker ps
複製程式碼
檢視本地所有的容器(不管是否執行),使用命令:
docker ps -a
複製程式碼
由於我本地暫未有容器,所以兩個命令結果都為空。結果中的表頭含義依次為:容器 ID
、使用的映象
、啟動容器時執行的命令
、容器的建立時間
、容器狀態
、容器的埠資訊和使用的連線型別
和 容器名稱
。
建立並啟動容器
容器是根據映象建立的,如果本地有映象,可以直接使用,如果沒有,會自動下載映象,然後再建立容器。建立容器使用命令:
docker run [OPTIONS] IMAGE [COMMAND]
複製程式碼
[OPTIONS]
是可選引數,IMAGE
是建立容器要根據的映象,[COMMAND]
是啟動容器後執行的命令,可選。
這裡說一下 OPTIONS
引數,官方提供了很多可選引數,我們不需要一開始就去認識所有的引數,後面遇到的會再說,這裡先只列舉幾個常用的瞭解一下:
-i
:以互動模式執行容器,保持容器執行狀態,通常與-t
同時使用;-t
:為容器重新分配一個偽終端,通常與-i
同時使用;-d
:以後臺模式執行容器,建立一個容器在後臺執行,需要使用docker exec
進入容器,退出後容器不會關閉;--name
:為建立的容器命名(注意這裡是長引數)。
現在舉例來建立一個容器,選取映象 centos
,使用以下命令:
docker run -it --name=c1 centos /bin/bash
複製程式碼
來分析下這句命令的含義:
首先引數 -it
是 -i -t
的合併寫法,linux 的基礎知識就不多說了,這兩個引數同時使用表示建立的是一個互動式容器,建立完成後會自動進入容器,退出容器後,容器會關閉。開始這裡可能不太明白什麼意思,往後看。
--name=c1
表示給這個容器取名為 c1
,也可以不加等號 --name c1
,另外如果不主動取名,會自動生成一個名字。
centos
是映象名稱,在使用一個映象前最好先搜尋是否有這個映象,同時我們也可以指定映象的版本,即 centos:7
。
/bin/bash
是一個命令,他會在建立容器完成並進入容器時執行,非必須。
現在我們在終端執行這句命令:
首先看圖中紅框裡,因為本地沒有 centos
這個映象,所以會自動在遠端倉庫拉取這個映象,並且因為沒指定版本,所以下載的是最新版的,之後就根據這個映象建立完成了容器。
建立完成後會自動進入容器裡,此時注意綠框中的命令提示符,顯然已經不是在宿主機的終端了,而是容器內部的終端(因為 -t 引數),所以此時再執行的命令只對容器內部有效。退出容器,可執行 exit
命令:
退出後可以看到命令提示符中顯示的又是宿主機了。需要知道的是,此時退出容器後,容器是關閉了的,再次強調一下使用 -it
引數建立的容器是互動式容器,退出即關閉,不信的話可以執行 docker ps
命令檢視執行中的容器,它並不在列。
上面這種互動式容器意味著我們不能退出,不然就關閉了,所以很多時候我們需要另外一種方式建立容器,讓它在後臺一直執行。
我們使用另外一種方式建立容器,使用命令:
docker run -id --name=c2 centos
複製程式碼
這條命令,使用 -d
引數替換掉了 -t
,表示建立的是一個後臺執行的容器,同時去除掉了 /bin/bash
命令,因為建立後不會進入容器,不需要執行命令。需要注意的是使用的還是同一個映象,同一個映象可以建立很多容器。
執行結果:
可以看到,建立完成後只返回了容器id,並沒有進入容器內部,命令提示符顯示還是在宿主機終端上。但此時這個容器是在執行的,使用 docker ps
來驗證:
我們可以進入容器來操作它,進入容器的命令是 docker exec
,我們先執行 docker exec --help
看看它有什麼要求:
可以看到它必須要跟上容器名和一個命令,所以我們可以執行:
docker exec c2 /bin/bash
複製程式碼
但是這樣執行,我們就拿不到一個可以在容器內部執行的終端,所以還需要加上 -it
引數,如下:
docker exec -it c2 /bin/bash
複製程式碼
還是根據命令提示符,我們已經進入到容器內部,此時同樣可以使用 exit
命令退出容器,但是此時退出並不會關閉容器,始終在後臺執行,只能手動關閉(關閉容器命令後面說)。
需要注意的是, docker exec
進入容器操作不是僅針對 -id
形式建立的容器,使用 -it
形式建立的容器退出後,也是要用這個命令重新進入,並且進入之前需要手動啟動容器。
小結:此小節我們知道建立容器有兩種方式,使用 -it 引數建立的是互動式容器,建立完自動進入容器,退出時自動關閉容器。使用 -id 引數建立的是守護式容器,即建立完執行在後臺,需要使用 docker exec 進入容器,使用 exit 退出,並且退出時不會關閉容器。
啟動/停止容器
啟動容器,使用命令:
docker start 容器ID或者容器名
複製程式碼
停止容器,使用命令:
docker stop 容器ID或者容器名
複製程式碼
在使用之前可以先用 docker ps -a
來檢視容器的相關資訊。
刪除容器
刪除容器使用命令:
docker rm 容器ID或者容器名
複製程式碼
注意不能刪除正在執行的容器,需要先關閉容器,才能刪除。
如果要一次刪除所有容器,可以使用這個命令:
docker rm `docker ps -aq`
複製程式碼
docker ps -aq
表示查詢所有容器的id,然後將結果傳給 docker rm
,以完成刪除所有。需要注意這裡刪除所有的前提是所有的容器都處於關閉狀態。
檢視某容器資訊
要檢視某一個容器的資訊,可以使用命令:
docker inspect 容器ID或者容器名
複製程式碼
資料卷
資料卷是什麼?
資料卷簡單來說,就是宿主機中的一個特殊目錄,它會與容器內目錄形成對映關係。用一張圖來表示層級關係如下:
資料卷有什麼用?
有這樣一個問題是否想過,就是當容器刪除後,它產生的資料是否會銷燬?答案是肯定的,因為容器是隔離執行的,資料也是產生在容器內部而不是在宿主機上,當容器被銷燬時,所產生的資料也會被銷燬。這顯然是不安全的,我們需要對容器資料進行備份。而資料卷的作用就是用來做資料持久化的,它完全獨立與容器的生命週期,容器刪除時也不會刪除其掛載的資料卷。
配置資料卷的方式其實就是在建立容器的同時,使用 -v
引數來配置,方式如下:
docker run ... -v 宿主機資料夾:容器內資料夾 ...
複製程式碼
注意事項:
- 資料夾路徑要是絕對路徑
- 如果資料夾不存在,會自動建立
- 可以掛載多個資料卷,幾多次使用
-v
引數
來舉個例子:
docker run -it --name=c1 -v ~/data:/root/data_container centos /bin/bash
複製程式碼
建立完成後,可以在容器的 /root
中看到 data_container
這個資料夾。同時宿主機的 ~/data
資料夾也肯定存在了,它就是資料卷。
怎麼使用資料卷呢?其實當配置好了資料卷後,不管是在宿主機上的操作還是在容器中的操作,都會自動同步。來舉個例子,我們在容器 /root/data_container
目錄中建立一個檔案 test.txt
:
接下來,在新視窗檢視宿主機的 ~/data
目錄下是否有 test.txt
檔案:
顯然,檔案是被同步的。反過來在宿主機上的操作,也是同步到容器中的,這裡就不多演示了。
正是因為資料卷的這種同步功能,所以可以用來進行兩個容器之間的間接通訊,原理無非就是兩個容器同時掛載到一個資料卷中,誰修改了,另一個也會收到更新。
另外,你也可以掛載多個資料卷,像這樣:
docker run -it --name=c2 -v ~/data1:/root/data1 -v ~/data2:/root/data2 centos /bin/bash
複製程式碼
資料卷容器
資料卷容器首先是一個容器,它掛載資料卷,然後其他容器通過掛載這個容器實現資料共享。同樣用一張圖表示:
資料卷容器相當於起了一個橋樑作用,它掛載資料卷,然後其他容器間要通訊時就不需要一一再與資料卷掛載,直接掛載到資料卷容器上即可,簡化了操作。
首先我們來建立資料卷容器 c3,(注意我每次舉例前都清空了現有容器,所以一直能用重複的名稱,容器名大家隨意~)
docker run -it --name=c3 -v /volume centos /bin/bash
複製程式碼
與之前配置資料卷不同,這裡的 -v
引數後面只接了一個目錄,這個目錄是我們自定義的,它是屬於容器內的。強調一下,這個目錄是屬於容器內的,不是宿主機上的。此時建立後,宿主機上會自動生成一個目錄來對映(圖中的資料卷是自動生成的,不是手動配置的)。
當執行命令後,容器內部已經生成了 volume
目錄,現在我們回到宿主機環境,使用 docker inspect c3
命令來檢視此容器的一些資訊:
在 Mounts
陣列中,“Source” 後面的就是宿主機上的資料卷,它是建立資料卷容器時自動建立的,“Destination” 表示目標地址,就是我們建立資料卷容器的自定義的 volume
目錄。
然後我們在建立兩個容器:
docker run -it --name=c1 --volumes-from c3 centos /bin/bash
docker run -it --name=c2 --volumes-from c3 centos /bin/bash
複製程式碼
使用到了 --volumes-from
引數,使得新建立的容器可以訪問 c3資料卷容器 的資料卷,說白了就是授權 c1,c2 可以訪問 c3 的資料卷,實現資料共享。
當我們按照上面建立 c1 後,會發現目錄下存在 volume
這個目錄,說明繫結 c3 成功了,建立 c2 也是同理。
那麼現在就來驗證一下資料共享。我們在 c2 的 volume
目錄下建立一個 hello.txt
檔案,然後去檢視 c1,c3 以及宿主機上的目錄是否同步。
如圖所示,一切沒毛病。
使用 docker 安裝 nginx
這裡簡單演示一下使用 docker 來安裝 nginx。
拉取現有 nginx 映象,正常情況下載一個映象前應該去先搜尋,這裡略過,預設安裝最新版本:
docker pull nginx
複製程式碼
根據映象建立 nginx 的容器:
docker run -id --name=nginx_c -p 8080:80 nginx
複製程式碼
這裡又出現了一個新的引數 -p
,它的作用是埠對映,8080:80
的意思是將容器的 80 埠對映到宿主機的 8080 埠。
為什麼要埠對映?這是因為外部機器是不能直接訪問到容器,但是外部機器與宿主機是可以連線的,同時容器也可以與宿主機連線,所以為了在外部機器上可以遠端訪問到容器,我們需要把容器的服務埠對映到宿主機上。
執行命令之後,使用伺服器的 ip 加 8080 埠訪問測試,如下:
可以看到使用 docker 部署 nginx 是如此便捷。當然用於實際生產還需要一些配置,這裡先不多講了,以後慢慢來。
結尾
由於本人也是剛剛入門 docker ,所以文中有不對的地方還是希望各位童鞋們指出,先謝謝了。
docker 文章還會繼續出,一來是為了加深的印象,二來我喜歡分享學會的知識,如果對你有幫助,務必要給個贊哦~