docker run是啓動容器的方法,可以用三種指定的方式指定容器啓動時執行的命令。
(1)CMD指令
(2)ENTRYPOINT指令
(3)在docker run中命令行中指定
但是docker run並不能長期保持running狀態,我們經常需要進入到容器中去做一些工作,比如查看日誌、調試、啓動其他進程等。有兩種進入容器的方式:attach和exec。
docker attach
首先啓動一個容器,保持後臺長期運行
docker run -d ubuntu /bin/bash -c "while true; do sleep 1; echo i_am_a_container;done
首先檢查容器的ID
docker ps -a
CONTAINER ID就是容器的編號,其實就是容器ID前12個字符,又叫短ID
IMAGE就是base IMAGE
NAMES是容器的名稱,在啓動容器的時候可以通過 --name參數顯式的爲容器命名。
通過docker attach可以attach到容器啓動命令的終端。
docker attach 1e5cc7e3b22b
通過短ID attach到了容器的啓動命令終端,之後看到的是echo每秒輸出一次打印信息
可以通過ctl+p,然後ctl+q退出attach終端
docker exec
通過docker exec進入相同的容器
docker exec -it 1e5cc7e3b22b bash
說明
1、-it 以交互的形式打開終端,執行bash
2、可以像普通linux一樣執行命令,顯示了容器啓動的進程
3、退出容器
docker exec命令格式如下:
docker exec -it <container> bash |sh
attach vs exec
兩者的主要區別如下:
1、attch直接進入容器啓動命令的終端,不會啓動新的進程
2、exec則是在容器中打開新的終端,而且可以啓動新進程
3、如果想直接在終端中查看啓動命令的輸出,用attach,其他情況用exec
運行容器的最佳實踐
按用途容器大致可以分爲兩類:服務類容器和工具的容器
前者以daemon的形式運行,對外提供服務,比如Web Server、數據庫等。通過-d 以後臺的方式啓動這類容器是非常合適的,如果要排查問題,可以通過exec -it進入容器
後者容器通常能給我們提供一個臨時的工作環境,通常以run -it方式進行
工具類容器多使用基礎鏡像,例如busybox,debian,ubuntu等
總結如下:
(1)當CMD,Entypoint和docker run命令行指定的命令運行結束時,容器停止
(2)通過-d參數在後臺啓動容器
(3)通過exec -it可以進入容器並執行命令
容器生命週期
stop/start/restart容器
docker stop:停止運行中的容器,容器在docker host中其實就是一個進程,該命令本質上是像該進程發送一個SIGTERM信號,也可通過docker kill命令快速停止容器
docker start: 對於停止的容器。可以通過該命令進行啓動,會保留容器的第一次啓動時的參數
docker restart :重啓容器
pause/unpause容器
docker pause:讓容器暫停,如需要對容器的文件系統打快照
unpause:處於pause狀態的容器不會佔用CPU資源,直到通過dokcer unpause恢復運行
刪除容器
docker rm:使用docker一段時間後,host上可能會有大量已經退出的容器,這些容器依然會佔用host的文件系統資源,可以使用docker rm進行刪除
如果希望一次刪除多個容器,則可以使用如下命令
docker rm -v $(docker ps -aq -f status=exited)
容器的狀態機制
整個容器的生命週期狀態機制,如下所示:
資源限制
一個docker host上會運行若干容器,每個容器都需要cpu,內存和IO資源。Docker提供了類似的機制避免某個容器因佔用太多資源而影響到其他容器或者整個HOST的資源
內存限額
與操作系統類似,容器可使用的內存包括兩個部分:物理內存和swap。Docker通過下面的兩組參數來控制容器內存的使用量
(1)-m或 --memory:設置內存的使用限制
(2)--memory-swap:設置內存+swap的使用限制
例如:
docker run -m 200M --memory-swap=300M ubuntu
含義時允許該容器最多使用200M的內存和300MB的 swap。默認情況下,上面兩組參數爲-l,即對容器內存和swap的使用沒有限制
測試使用progrium/stress鏡像,該鏡像可以用於對容器執行壓力測試
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
說明:
1、--vm1:啓動1個內存工作線程
2、--vm-bytes 280M,每個線程分配280MB內存
過程:
1分配280M內存
2釋放280M內存
3再分配280M內存
4再釋放
5 一致持續循環
cpu限制
默認設置下,所有的容器可以平等的使用hostCPU資源,而且沒有限制
docker可以通過-c或者--cpu-shares設置容器使用cpu的權重,如果不指定,默認值1024
與內存限額不同,通過-c設置的cpu share並不是cpu資源的絕對數量,而是一個相對的權重值。某個容器最終能分配的到的CPU資源取決於它的cpu share總和和比例,換句話說通過cpu share可以設置容器使用CPU的優先級
docker run --name "container_A" -c 1024 ubuntu && docker run --name "container_B" -c 512 ubuntu
container_A的cpu share 1024,是containerB的兩倍,當兩個容器都需要CPU資源時,前者可以得到的cpu是後者的兩倍
需要特別注意的是,這種按權重分配CPU的只會發生在CPU資源緊張的情況下。如果containerA處於空閒狀態,這時爲了充分利用CPU資源,containrB也可以分配到全部可用的cpu
Block IO帶寬限制
Block IO是另一種可以限制容器資源,它是指磁盤的讀寫,docker可以通過設置權重,限制bsp和iops的方式控制容器讀寫磁盤的帶寬。
IO權重
默認情況下,所有的容器能平等的讀寫磁盤,可以通過設置 --blkio-weight 參數來改變容器的block IO的優先級
--blkio-weight與--cpu-share類似,設置的是相對權重,默認爲500
docker run -it --name container_A --blkio-weight 600 ubuntu && docker run --it --name container_B --blkio-weight 300 ubuntu
通過命令行設定,containerA的讀寫磁盤帶寬是containerB的兩倍
限制bps和iops
bsp是byte per second ,每秒讀寫的數據量
iops是ip per second,每秒IO的次數
可以通過以下參數控制容器的bsp和 iops
--device-read-bps,限制讀某個設備的 bps。
--device-write-bps,限制寫某個設備的 bps。
--device-read-iops,限制讀某個設備的 iops。
--device-write-iops,限制寫某個設備的 iops。
cgroup和namespace
cgropu和namespace是實現容器底層的最重要的兩種技術。cgroup實現資源限制,namespace實現資源的隔離
cgroup
cgroup 全稱 Control Group。Linux 操作系統通過 cgroup 可以設置進程使用 CPU、內存 和 IO 資源的限額。前面我們看到的--cpu-shares、-m、--device-write-bps 實際上就是在配置 cgroup。
可以在/sys/fs/cgroup中找到
docker run -it --cpu-shares 512 progrium/stress -c 1
記錄容器ID。在 /sys/fs/cgrouXXXpu/docker 目錄中,Linux 會爲每個容器創建一個 cgroup 目錄,以容器長ID 命名:
目錄中包含所有與 cpu 相關的 cgroup 配置,文件 cpu.shares 保存的就是 --cpu-shares 的配置,值爲 512。
同樣的,/sys/fs/cgroup/memory/docker 和 /sys/fs/cgroup/blkio/docker 中保存的是內存以及 Block IO 的 cgroup 配置
namespace
在每個容器中,我們都可以看到文件系統,網卡等資源,這些資源看上去是容器自己的。拿網卡來說,每個容器都會認爲自己有一塊獨立的網卡,即使 host 上只有一塊物理網卡。這種方式非常好,它使得容器更像一個獨立的計算機。
Linux 實現這種方式的技術是 namespace。namespace 管理着 host 中全局唯一的資源,並可以讓每個容器都覺得只有自己在使用它。換句話說,namespace 實現了容器間資源的隔離。
Linux 使用了六種 namespace,分別對應六種資源:Mount、UTS、I*、PID、Network 和 User。
Mount namespace
Mount namespace 讓容器看上去擁有整個文件系統。
容器有自己的 / 目錄,可以執行 mount 和 umount 命令。當然我們知道這些操作只在當前容器中生效,不會影響到 host 和其他容器。
UTS namespace
簡單的說,UTS namespace 讓容器有自己的 hostname。 默認情況下,容器的 hostname 是它的短ID,可以通過 -h 或 --hostname 參數設置。
I P C namespace
IPC namespace 讓容器擁有自己的共享內存和信號量(semaphore)來實現進程間通信,而不會與 host 和其他容器的 IPC 混在一起。
PID namespace
能夠使容器能夠擁有自己的PID
Network namespace
Network namespace 讓容器擁有自己獨立的網卡、IP、路由等資源。我們會在後面網絡章節詳細討論。
User namespace
User namespace 讓容器能夠管理自己的用戶,host 不能看到容器中創建的用戶。
常用命令
以下是容器的常用操作命令
create 創建容器
run 運行容器
pause 暫停容器
unpause 取消暫停繼續運行容器
stop 發送 SIGTERM 停止容器
kill 發送 SIGKILL 快速停止容器
start 啓動容器
restart 重啓容器
attach attach 到容器啓動進程的終端
exec 在容器中啓動新進程,通常使用 "-it" 參數
logs 顯示容器啓動進程的控制檯輸出,用 "-f" 持續打印
rm 從磁盤中刪除容器