《前端運維》三、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中的一條指令。
下面我們來學習下一些基本的命令:
- docker image ls,查看全部鏡像。字段含義如下:
REPOSITORY 倉庫地址 TAG 標籤 IMAGE_ID 鏡像ID CREATED 創建時間 SIZE 鏡像大小 - docker search [imageName],查找鏡像。字段含義如下:
字段 含義 NAME 名稱 DESCRIPTION 描述 STARTS 星星的數量 OFFICIAL 是否官方源 - docker history [imageName],查看鏡像歷史。
- docker inspect [imageName],顯示一個或多個鏡像信息。
- docker pull [imageName],拉取鏡像。
- docker push [imageName],推送一個鏡像到鏡像倉庫。
- docker rmi [imageName],刪除鏡像。
- docker image prune,移除未使用的鏡像,沒有標記或被任何容器引用。
- tag,標記本地鏡像,將其歸入某一倉庫
- 語法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]。
- 例子:docker tag centos:7 zaking/centos:v1。
- export,將容器文件系統作為一個tar歸檔文件導出到STDOUT。
- 語法:docker export [OPTIONS] CONTAINER。
- docker export -o hello-world.tar b2712f1067a3。
- import,導入容器快照文件系統tar歸檔文件並創建鏡像。
- 語法:docker import [OPTIONS] file/URL/- [REPOSITORY[:TAG]。
- 例子:docker import hello-world.tar。
- save,將指定文件保存成tar文件。
- 語法:docker save [OPTIONS] IMAGE [IMAGE…]。
- docker save -o hello-world.tar hello-world:latest。
- load,加載tar文件並創建鏡像。
- 例子:docker load -i hello-world.tar。
- 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鏡像文件和容器文件。關閉容器並不會刪除容器文件,只是停止容器的運行。
下面,我們來學習一下容器有關的命令:
- 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:。
- docker ps:查看容器。
- 參數:
- -a:顯示所有的容器,包括已停止的。
- -l:顯示最新的那個容器。
字段 含義 CONTAINER ID 容器ID IMAGE 使用的鏡像 COMMAND 使用的命令 CREATED 創建時間 STATUS 狀態 PORTS 端口號 NAMES 自動分配的名稱
- 參數:
- docker run -i -t ubuntu /bin/bash:運行交互式的容器。可以通過exit命令或CTRL+D退出交互界面。
- -t=–interactive 在新容器內指定一個偽終端或終端。
- -i=–tty 允許你對容器內的標準輸入 (STDIN) 進行交互。
- docker kill:kill是不管容器同不同意,直接執行
kill -9
,強行終止;stop的話,首先給容器發送一個TERM
信號,讓容器做一些退出前必須的保護性、安全性操作,然後讓容器自動停止運行,如果在一段時間內,容器還是沒有停止,再進行kill -9,強行終止。- 例子:docker kill 5a5c3a760f61。
- docker rm:刪除容器。
- 例子:docker rm 5a5c3a760f61。
- docker rm $(docker ps -a -q)。刪除所有的容器,-a,所有的,-q顯示id號。就是批量刪除所有的意思。
- docker start [containerId]:啟動容器。
- docker stop [containerId]:停止容器。
- docker attach [containerID]:進入一個容器。
- docker container -exec -it [containerID] /bin/bash:進入一個正在進行中的容器。
- docker container cp [containerID]/readme.md .:拷貝文件。
- docker run –rm ubuntu /bin/bash:自動刪除。
- docker container stats:顯示容器資源使用統計。
- docker container top:顯示一個容器運行的進程。
- docker update -m 500m 6d1a25f95132:更新一個或多個容器配置。
- 列出指定的容器的端口映射:
docker run -d -p 8080:80 nginx docker container port containerID
-
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 [你自己剛才生成的鏡像名字]
然後,在另一個終端訪問下:
直接就出來了,不需要我們再重新創建了。當然,如果要發佈到遠程倉庫,需要註冊賬號。這個我就不多說了,大家有興趣可以自己試一下。
好啦,關於容器和鏡像的部分。就先到這裡了。