docker 入門上篇

黑色瓶子發表於2020-02-24

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(關於映象,後面會說),由於國內網路原因,我們在拉取一些已有映象時會遇到困難,所以需要配置加速器。加速器有很多種,這裡推薦使用阿里雲的加速器,它是免費的,不需要購買任何東西。

登入阿里雲後搜尋關鍵詞 映象服務,選擇容器映象服務:

docker 入門上篇

第一次使用時,會讓你設定登入密碼,設定一下即可:

docker 入門上篇

然後在左側選單點選映象加速器,右邊可以看到給你提供了一個加速地址,這個地址每個人的都不一樣。阿里雲很貼心地在下方給出直接執行的命令程式碼,選擇你的平臺,複製貼上所有程式碼,直接執行在終端即可:

docker 入門上篇

執行結束後,可以使用命令 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容器,可以用一張圖來了解:

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

docker 入門上篇

綠色部分的 active (running) 就表示 docker 正在執行,我們再來停止一次服務,並檢視狀態:

docker 入門上篇

如圖,inactive (dead) 就表示 docker 服務已停止。再試下重啟服務:

docker 入門上篇

開機啟動命令這裡就不演示了。

映象命令

映象命令用於操作映象(images)相關。

檢視映象

檢視本地所有映象,可使用命令:

docker images
複製程式碼

docker 入門上篇
可以看到我的本地有一個 redis 的映象,這是因為我提前安裝了,如果沒安裝就是空的。顯示結果的第一行是表頭,分別表示為映象名稱版本號映象 id建立時間映象大小

檢視所有映象的 id,可以使用命令:

docker images -q
複製程式碼

docker 入門上篇

我這裡只有一個映象,所以只顯示了一個 id,如果有多個映象的話會顯示所有的映象 id。

搜尋映象

有時候我們並不知道庫裡是否有我們需要的映象,這時候就需要先搜尋,使用命令:

docker search 映象名稱
複製程式碼

比如我們來搜尋 redis

docker 入門上篇

如圖所示,會將所有 redis 相關源資訊列印出來,第一行依舊是頭,依次表示為:名稱描述star 數是否是官方出的自動構建

拉取映象

拉取映象即從 docker 倉庫下載映象到本地,使用命令:

docker pull 映象名稱
複製程式碼

或者下載指定版本:

docker pull 映象名稱:版本號
複製程式碼

注意,當不指定版本號時,預設下載最新版本(latest版)。另外要指定下載某個版本時,可以去 DockerHub 檢視映象對應的一些版本號,不要隨便自定義版本號。下載就不演示了。

刪除映象

刪除指定映象,使用命令:

docker rmi 映象id
複製程式碼

注意這裡是要指定映象的 id ,而不是名稱。我們可以先使用 docker images 來檢視映象的id,然後再來刪除。刪除 redis 測試:

docker 入門上篇

第一步檢視所有映象時,顯示有兩個映象,刪除 redis 後再檢視時只有一個了,說明刪除成功。

另外,當一次刪除多個映象時,可以將映象id依次輸入進去,這樣:

docker rmi id1 id2 id3...
複製程式碼

當要刪除所有的映象時,可以使用這樣一個組合命令:

docker rmi `docker images -q`
複製程式碼

這句命令的意思很明顯,就是將 docker images -q 查詢到的所有映象 id 傳給刪除命令,以達到刪除所有映象的效果。

容器命令

容器命令用於操控容器相關,是比較重要的部分,我們最終直接用於生產的也就是容器。

檢視容器

檢視本地所有正在執行中的容器,使用命令:

docker ps
複製程式碼

檢視本地所有的容器(不管是否執行),使用命令:

docker ps -a
複製程式碼

docker 入門上篇

由於我本地暫未有容器,所以兩個命令結果都為空。結果中的表頭含義依次為:容器 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 是一個命令,他會在建立容器完成並進入容器時執行,非必須。

現在我們在終端執行這句命令:

docker 入門上篇

首先看圖中紅框裡,因為本地沒有 centos 這個映象,所以會自動在遠端倉庫拉取這個映象,並且因為沒指定版本,所以下載的是最新版的,之後就根據這個映象建立完成了容器。

建立完成後會自動進入容器裡,此時注意綠框中的命令提示符,顯然已經不是在宿主機的終端了,而是容器內部的終端(因為 -t 引數),所以此時再執行的命令只對容器內部有效。退出容器,可執行 exit 命令:

docker 入門上篇

退出後可以看到命令提示符中顯示的又是宿主機了。需要知道的是,此時退出容器後,容器是關閉了的,再次強調一下使用 -it 引數建立的容器是互動式容器,退出即關閉,不信的話可以執行 docker ps 命令檢視執行中的容器,它並不在列。

上面這種互動式容器意味著我們不能退出,不然就關閉了,所以很多時候我們需要另外一種方式建立容器,讓它在後臺一直執行。

我們使用另外一種方式建立容器,使用命令:

docker run -id --name=c2 centos
複製程式碼

這條命令,使用 -d 引數替換掉了 -t,表示建立的是一個後臺執行的容器,同時去除掉了 /bin/bash命令,因為建立後不會進入容器,不需要執行命令。需要注意的是使用的還是同一個映象,同一個映象可以建立很多容器。

執行結果:

docker 入門上篇

可以看到,建立完成後只返回了容器id,並沒有進入容器內部,命令提示符顯示還是在宿主機終端上。但此時這個容器是在執行的,使用 docker ps 來驗證:

docker 入門上篇

我們可以進入容器來操作它,進入容器的命令是 docker exec,我們先執行 docker exec --help 看看它有什麼要求:

docker 入門上篇

可以看到它必須要跟上容器名和一個命令,所以我們可以執行:

docker exec c2 /bin/bash
複製程式碼

但是這樣執行,我們就拿不到一個可以在容器內部執行的終端,所以還需要加上 -it 引數,如下:

docker exec -it c2 /bin/bash
複製程式碼

docker 入門上篇

還是根據命令提示符,我們已經進入到容器內部,此時同樣可以使用 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或者容器名
複製程式碼

資料卷

資料卷是什麼?

資料卷簡單來說,就是宿主機中的一個特殊目錄,它會與容器內目錄形成對映關係。用一張圖來表示層級關係如下:

docker 入門上篇

資料卷有什麼用?

有這樣一個問題是否想過,就是當容器刪除後,它產生的資料是否會銷燬?答案是肯定的,因為容器是隔離執行的,資料也是產生在容器內部而不是在宿主機上,當容器被銷燬時,所產生的資料也會被銷燬。這顯然是不安全的,我們需要對容器資料進行備份。而資料卷的作用就是用來做資料持久化的,它完全獨立與容器的生命週期,容器刪除時也不會刪除其掛載的資料卷。

配置資料卷的方式其實就是在建立容器的同時,使用 -v 引數來配置,方式如下:

docker run ... -v 宿主機資料夾:容器內資料夾 ...
複製程式碼

注意事項:

  • 資料夾路徑要是絕對路徑
  • 如果資料夾不存在,會自動建立
  • 可以掛載多個資料卷,幾多次使用 -v 引數

來舉個例子:

docker run -it --name=c1 -v ~/data:/root/data_container centos /bin/bash
複製程式碼

docker 入門上篇

建立完成後,可以在容器的 /root 中看到 data_container 這個資料夾。同時宿主機的 ~/data 資料夾也肯定存在了,它就是資料卷。

怎麼使用資料卷呢?其實當配置好了資料卷後,不管是在宿主機上的操作還是在容器中的操作,都會自動同步。來舉個例子,我們在容器 /root/data_container 目錄中建立一個檔案 test.txt

docker 入門上篇

接下來,在新視窗檢視宿主機的 ~/data 目錄下是否有 test.txt 檔案:

docker 入門上篇

顯然,檔案是被同步的。反過來在宿主機上的操作,也是同步到容器中的,這裡就不多演示了。

正是因為資料卷的這種同步功能,所以可以用來進行兩個容器之間的間接通訊,原理無非就是兩個容器同時掛載到一個資料卷中,誰修改了,另一個也會收到更新。

另外,你也可以掛載多個資料卷,像這樣:

docker run -it --name=c2 -v ~/data1:/root/data1 -v ~/data2:/root/data2 centos /bin/bash
複製程式碼

資料卷容器

資料卷容器首先是一個容器,它掛載資料卷,然後其他容器通過掛載這個容器實現資料共享。同樣用一張圖表示:

docker 入門上篇

資料卷容器相當於起了一個橋樑作用,它掛載資料卷,然後其他容器間要通訊時就不需要一一再與資料卷掛載,直接掛載到資料卷容器上即可,簡化了操作。

首先我們來建立資料卷容器 c3,(注意我每次舉例前都清空了現有容器,所以一直能用重複的名稱,容器名大家隨意~)

docker run -it --name=c3 -v /volume centos /bin/bash
複製程式碼

與之前配置資料卷不同,這裡的 -v 引數後面只接了一個目錄,這個目錄是我們自定義的,它是屬於容器內的。強調一下,這個目錄是屬於容器內的,不是宿主機上的。此時建立後,宿主機上會自動生成一個目錄來對映(圖中的資料卷是自動生成的,不是手動配置的)。

docker 入門上篇

當執行命令後,容器內部已經生成了 volume 目錄,現在我們回到宿主機環境,使用 docker inspect c3 命令來檢視此容器的一些資訊:

docker 入門上篇

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 的資料卷,實現資料共享。

docker 入門上篇

當我們按照上面建立 c1 後,會發現目錄下存在 volume 這個目錄,說明繫結 c3 成功了,建立 c2 也是同理。

那麼現在就來驗證一下資料共享。我們在 c2 的 volume 目錄下建立一個 hello.txt 檔案,然後去檢視 c1,c3 以及宿主機上的目錄是否同步。

docker 入門上篇

docker 入門上篇

如圖所示,一切沒毛病。

使用 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 入門上篇

可以看到使用 docker 部署 nginx 是如此便捷。當然用於實際生產還需要一些配置,這裡先不多講了,以後慢慢來。

結尾

由於本人也是剛剛入門 docker ,所以文中有不對的地方還是希望各位童鞋們指出,先謝謝了。

docker 文章還會繼續出,一來是為了加深的印象,二來我喜歡分享學會的知識,如果對你有幫助,務必要給個贊哦~

相關文章