《前端運維》三、Docker–1鏡像與容器

  • 2022 年 3 月 25 日
  • 筆記

一、基本概念

  如果我們想要讓軟件運行起來,首先要保證操作系統的設置,其次還需要依賴各種組件和庫的正確安裝。那麼虛擬機就是一種帶環境安裝的一種解決方案,它可以實現在一種操作系統裏面運行另外一種操作系統,但是虛擬機的缺點也是十分明顯的,資源佔用多、冗餘步驟多、啟動速度慢。由於虛擬機存在的這些令人詬病的缺點。Linux發展出了另一種虛擬化技術,Linux Containers,即Linux容器,縮寫為LXC。

  Linux容器並沒有虛擬一個完整的操作系統,而是對進程進行隔離。或者說,在正常進程的外面套了一層保護層。對於容器裏面的進程來說,它接觸到的各種資源都是虛擬的,從而實現與底層系統的隔離。Linux的容器也十分明顯,體積小、啟動快、資源佔用也是極少的。

  Docker屬於Linux容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的Linux容器解決方案。Docker將應用程序與該程序的依賴,打包在一個文件裏面。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裏面運行,就好像在真實的物理機上運行一樣。

  同時Docker的應用場景也十分廣泛,比如:單項目打包、整套項目打包、新開源技術、環境一致性、持續集成、微服務、彈性伸縮等。

  下面我們來看一張圖,來學習下Docker體系的結構:

  我們看上圖哦,Docker通過Docker Client的客戶端發送指令,驅動Docker Engine引擎來啟動容器,然後通過Containerd來管理對應容器的內容,然後,shim只用來管理每個獨立的容器,通過runC這個輕量級的工具來啟動容器。在啟動容器的時候,可能會去Image Repository鏡像倉庫中去取對應的依賴。

  Docker提供了一些內部的組件,我們也需要了解一下:

  • namespaces,命名空間,Linux內核提供的一種對進程資源隔離的機制,例如進程、網絡、掛載等資源。
  • cgroups,控制組,linux內核提供的一種限制進程資源的機制,例如cpu、內存等資源。
  • unonFS,聯合文件系統,支持將不同位置的目錄掛載到同一虛擬文件系統中,形成一種分層的模型。

二、Docker安裝

  首先docker的版本類型上,分為企業版和社區版,咱們用社區版就可以了,企業版是付費的。它的安裝文檔地址在://docs.docker.com/engine/install/centos/

  我們通過下面的命令來安裝下docker:

  先安裝docker的一些依賴:

yum install -y yum-utils   device-mapper-persistent-data   lvm2

  再安裝docker的安裝源:

yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo

  最後安裝docker:

yum install docker-ce docker-ce-cli containerd.io -y

  這樣,我們的docker就安裝好了。然後我們看下常用的一些命令:

# 啟動docker
systemctl start docker
# 查看docker信息
docker version
docker info
# 卸載docker
yum remove docker
# 刪除docker相關的文件夾
rm -rf /var/lib/docker

  我們也可以把相關的軟件依賴改成阿里雲的鏡像地址,這樣下載的時候會快一些,我就不多說了,因為我沒改:

# 創建一個文件
sudo mkdir -p /etc/docker
# 寫入一些配置
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["//fwvjnv59.mirror.aliyuncs.com"]
}
EOF
# 重載所有修改過的配置文件 
# daemon-reload: 重新加載某個服務的配置文件
sudo systemctl daemon-reload
sudo systemctl restart docker

三、Docker鏡像

   Docker把應用程序及其依賴,打包再image鏡像文件裏面,只有通過這個文件,才能生成Docker容器。image鏡像文件可以看作是容器的模板。Docker根據image鏡像文件生成容器的實例。同一個image鏡像文件,可以生成多個同時運行的image實例。鏡像文件不是一個單一的文件,而是有多層次的結構。容器其實就是在image鏡像的最上面一層加了一層讀寫層。在運行容器里做的任何文件改動,都會寫到這個讀寫層里。如果容器刪除了,最上面的讀寫層也就刪除了,改動也就丟失了。

  我們可以通過docker history [id/name] 查看鏡像中各層級的內容及大小,每層對應着dockerfile中的一條指令。

  下面我們來學習下一些基本的命令:

  1. docker image ls,查看全部鏡像。字段含義如下:
    REPOSITORY 倉庫地址
    TAG 標籤
    IMAGE_ID 鏡像ID
    CREATED 創建時間
    SIZE 鏡像大小
  2. docker search [imageName],查找鏡像。字段含義如下:
    字段 含義
    NAME 名稱
    DESCRIPTION 描述
    STARTS 星星的數量
    OFFICIAL 是否官方源
  3. docker history [imageName],查看鏡像歷史。
  4. docker inspect [imageName],顯示一個或多個鏡像信息。
  5. docker pull [imageName],拉取鏡像。
  6. docker push [imageName],推送一個鏡像到鏡像倉庫。
  7. docker rmi [imageName],刪除鏡像。
  8. docker image prune,移除未使用的鏡像,沒有標記或被任何容器引用。
  9. tag,標記本地鏡像,將其歸入某一倉庫
    • 語法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]。
    • 例子:docker tag centos:7 zaking/centos:v1。
  10. export,將容器文件系統作為一個tar歸檔文件導出到STDOUT。
    • 語法:docker export [OPTIONS] CONTAINER。
    • docker export -o hello-world.tar b2712f1067a3。
  11. import,導入容器快照文件系統tar歸檔文件並創建鏡像。
    • 語法:docker import [OPTIONS] file/URL/- [REPOSITORY[:TAG]。
    • 例子:docker import hello-world.tar。
  12. save,將指定文件保存成tar文件。
    • 語法:docker save [OPTIONS] IMAGE [IMAGE…]。
    • docker save -o hello-world.tar hello-world:latest。
  13. load,加載tar文件並創建鏡像。
    • 例子:docker load -i hello-world.tar。
  14. build,根據Dockerfile構建鏡像。
    • 語法:docker build [OPTIONS] PATH / URL / -。
    • 例子:docker build -t zf/ubuntu:v1。

  然後,我們學習了一些相關的命令,下面我們來拿這些命令做一些實踐:

  首先,我們查找一下centos鏡像:

docker search centos

  然後,我們把centos的鏡像拉取到本地,如果你這裡下載很慢的話,請回頭安裝阿里源,嘻嘻:

docker pull centos

  然後,我們可以使用fs命令,查看下現在有哪些鏡像:

docker image ls

  下一步我們從遠程鏡像倉庫拉取一個docker官方的例子鏡像到本地的鏡像倉庫:

docker pull docker.io/hello-world

  然後,可以通過rmi命令,刪除本地鏡像:

docker rmi hello-world

 

四、Docker容器

   首先,我們來學習下一些有關於容器的基本概念。docker run 命令會從image鏡像文件中生成一個正在運行的容器實例。該命令具有自動抓取image鏡像文件的功能,如果發現本地沒有指定的image文件,就會從倉庫自動抓取。輸出提示後,實例就會停止運行,容器自動終止,當然,並不是所有的容器都會自動終止。同過image鏡像文件生成的生成的容器實例,本身也是一個文件,成為容器文件。生成了容器後,就會同時存在兩個文件,image鏡像文件和容器文件。關閉容器並不會刪除容器文件,只是停止容器的運行。

  下面,我們來學習一下容器有關的命令:

  1. docker run:啟動容器。
    • 例子:docker run ubuntu /bin/echo ‘hello world’。這句話的意思就是,通過ubuntu鏡像生成一個容器,在容器中執行/bin/echo ‘helloworld’的命令。我們看下圖,當我們想要執行的命令在容器中打印後,該容器就自動終止了。這就是我們上面說到的含義。另外,如果本地沒有對應的鏡像,docker會自動去docker hub拉取。
    • 參數:
      • -i,–interactive:交互式。
      • -t,-tty:分配一個偽終端。
      • -d,–detach:運行容器到後台。
      • -a,–attach list:附加到運行的容器。
      • -e,–env list:設置環境變量。
      • -p,–publish list:發佈容器端口到主機。
      • -P,–publish-all:。
  2. docker ps:查看容器。
    • 參數:
      • -a:顯示所有的容器,包括已停止的。
      • -l:顯示最新的那個容器。
        字段 含義
        CONTAINER ID 容器ID
        IMAGE 使用的鏡像
        COMMAND 使用的命令
        CREATED 創建時間
        STATUS 狀態
        PORTS 端口號
        NAMES 自動分配的名稱
  3. docker run -i -t ubuntu /bin/bash:運行交互式的容器。可以通過exit命令或CTRL+D退出交互界面。
    • -t=–interactive 在新容器內指定一個偽終端或終端。
    • -i=–tty 允許你對容器內的標準輸入 (STDIN) 進行交互。
  4. docker kill:kill是不管容器同不同意,直接執行kill -9,強行終止;stop的話,首先給容器發送一個TERM信號,讓容器做一些退出前必須的保護性、安全性操作,然後讓容器自動停止運行,如果在一段時間內,容器還是沒有停止,再進行kill -9,強行終止。
    • 例子:docker kill 5a5c3a760f61。
  5. docker rm:刪除容器
    • 例子:docker rm 5a5c3a760f61。
    • docker rm $(docker ps -a -q)。刪除所有的容器,-a,所有的,-q顯示id號。就是批量刪除所有的意思。
  6. docker start [containerId]:啟動容器
  7. docker stop [containerId]:停止容器。
  8. docker attach [containerID]:進入一個容器。
  9. docker container -exec -it [containerID] /bin/bash:進入一個正在進行中的容器。
  10. docker container cp [containerID]/readme.md .:拷貝文件。
  11. docker run –rm ubuntu /bin/bash:自動刪除。
  12. docker container stats:顯示容器資源使用統計。
  13. docker container top:顯示一個容器運行的進程。
  14. docker update -m 500m 6d1a25f95132:更新一個或多個容器配置。
  15. 列出指定的容器的端口映射:
    docker run -d -p 8080:80 nginx 
    docker container port containerID 
  16. docker logs [containerId]:查看docker容器的輸出。

  下面,我們把上面學習的命令來實踐一下:

  剛才我們在學習run命令的時候已經啟動了一個容器並打印出了命令,那個是最基礎的方法,那下面,我們來查看下我們的容器都有哪些:

docker ps -a

   哈,只有一個,就是我們剛才執行的那個。下面我們來試一下啟動一個交互式的容器:

docker run -i -t ubuntu /bin/bash 

  我們就進入了交互式容器的偽終端里,可以進行命令交互。然後我們執行下面的命令:

docker run centos ping www.baidu.com

  執行了這個命令後,就會一直ping www.baidu.com,別的事就幹不了了,只能看着:

  此時,我們就需要–detach參數,進入後台運行:

docker run --detach centos ping www.baidu.com

  然後,這個容器就會在後台運行:

   那,我想要查看這個容器裏面的日誌怎麼辦呢,通過下面的命令就可以查看對應容器里的日誌了:

docker logs --follow [id/name]

  當然,我們也可以通過attach,重新進入這個容器。

docker attach [id]

  然後,可以通過stop命令,停止某個正在運行中的容器:

docker stop [containerId]

   docker stop是否能停止,是由容器內部指定的,需要運行完一些必要的容器才會停止。如果你希望可以立即殺死該容器,直接強行終止,就使用kill命令。停止了以後,我們可以通過docker start來重新啟動。

  然後,我們可以通過rm命令,刪除已有的容器:

docker ps -a

  先通過ps命令看下目前容器的id,然後通過rm刪除:

docker rm [id]

  這樣一個一個刪除太慢了,我們可以通過下面的命令批量刪除:

docker rm $(docker ps -a -q)

  很簡單吧。

 

1、其它命令實踐:

  下面我們來練習下其他命令,我們先啟動個hello-world的容器:

docker run hello-world

  然後我們把這個容器導出:

docker export -o hello-world.tar [cantainerId]

  然後我們看下這個文件:  

   刪除這個容器:

docker rm [containerId]

  然後鏡像文件也刪除掉:

docker rmi hello-world

   然後,我們可以通過import命令,把剛才導出的tar包,再導入回來:

docker import hello-world.tar

   就是這個了。

   save命令可以把指定鏡像打包成tar文件:

docker save -o redis.tar redis:latest

  然後刪除你剛才打包成tar的鏡像,怎麼刪除我就不說了啊。刪除了之後,我們可以通過load命令,把剛才的tar包下載回來。

docker load -i redis.tar

  用戶既可以使用 docker load 來導入鏡像存儲文件到本地鏡像庫,也可以使用 docker import 來導入一個容器快照到本地鏡像庫。這兩者的區別在於容器(import)快照文件將丟棄所有的歷史記錄和元數據信息(即僅保存容器當時的快照狀態),而鏡像(load)存儲文件將保存完整記錄,體積也要大。此外,從容器(import)快照文件導入時可以重新指定標籤等元數據信息。

 2、下面我們來實踐一些容器相關的:

  我們先後台跑起來前面的那個ping命令:

docker run --detach centos ping www.baidu.com

  然後,我們來用stats看下它的狀態:

docker stats [containerId]

   然後可以通過top命令,查看一個運行中容器的進程:

docker top [containerId]

   我們還可以使用update命令更新一個或多個容器的配置,看stats那個圖,LIMIT是1.7G左右,我們來通過update命令,限制一下它的內存:

docker update -m 500m [containerId]

   可惜報錯了,他跟你說還要同時設置memoryswap,設置一下唄:

   然後LIMIT就變成了500M,簡單吧。

3、下面我們來實踐下如何映射指定容器的端口:

  先使用下面的命令,啟動一個docker容器中的nginx:

docker run -d -P nginx

  這樣會自動指定與宿主機的端口映射。

   圖中紅框的部分就是自動指定的與宿主機的映射,我們也可以手動設置:

docker run -d -p 8080:80

   這個意思就是說宿主機的ip是8080端口映射到docker容器的nginx的80端口。

4、學習下如何commit命令製作個性化鏡像:

  我們先停止並刪除之前所有的容器:

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

  然後像之前的例子一樣,啟動一個nginx容器。

  通過下面的命令進入到容器的偽終端中:

docker exec -it [containerId]/bin/bash

  然後,我們進入到容器的nginx存儲html文件的目錄,/usr/share/nginx/html:

cd /usr/share/nginx/html

  創建一個html文件:

echo hello > hello.html

  然後我們再打開一個命令行,訪問一下剛才的nginx服務,要注意查看端口號哦:

   這樣就成功了。下面看下如何基於這個容器,建一個新的鏡像:

docker commit -m'zakings nginx' -a'zaking' 0a90e57ca86b zaking/zakingnginx

  這段代碼是什麼意思呢,docker commit -m’描述信息’ -a’作者信息’ [containerId] [包名]。

   我們可以查看下:

   多了我們剛才生成的鏡像。下面我們清空下容器,使用我們自己創建的鏡像創建容器:

   不多說了,實踐好多遍了。

  然後呢,實際上就是跟之前的方式一樣,創建nginx容器,並自動設置端口號就好了:

docker run -d -P [你自己剛才生成的鏡像名字]

   然後,在另一個終端訪問下:

   直接就出來了,不需要我們再重新創建了。當然,如果要發佈到遠程倉庫,需要註冊賬號。這個我就不多說了,大家有興趣可以自己試一下。

  好啦,關於容器和鏡像的部分。就先到這裡了。