前言
這是我讀了「Docker這樣學才有趣」這本書其中第1章~第5章的筆記,這幾章包含了 Docker基本知識與指令、Dockerfiler以及 Docker Compose指令等,已經足以建置一般的 Docker Container以及自動化管理。不過docker-compose.yml文件指令的部份實在是太多了… 一時間筆記做不完,所以尚未寫好…
後面的章節內容還有架設 Docker Registry,以及多個範例實作(也就是標題上說有趣的部份),就被我跳過了…
CH1 Docker的能與不能
Container(容器)的完整名稱應該是「Linux Containers」,指的是一組利用 Linux核心提供的技術來達到把程式或軟體「包裏」在一個可隔離且獨立運行的環境工具。
Docker就是用來管理這些 Containers的工具
Docker是一個完全免費(採用 Apache 2.0授權)的開發原始碼專案
↑ moby是容器框架,原本 github上的 docker專案已改名為 moby,而 Docker是使用 moby架構實作出來的產品
https://kknews.cc/zh-tw/tech/gv63368.html
版本及差異:
Docker EE(Docker Enterprise Edition,企業版):付費版
Docker CE(Docker Community Edition,社群版):免費版
Docker Desktop:由於 Docker是基於 Linux的 Container工具,所以 Linux以外的作業系統 - Mac和 Windows必須安裝 Docker Desktop。其原理是在透過 Linux虛擬機器來運行 Container的。目前 Docker Desktop僅提供250以下小型公司免費版本,大型公司必須使用付費方案。
CH2 必學的 Docker功能與指令
下載及啟用 Image(映象檔)
映像檔相關名詞:
- Docker Image:透過 Docker把要使用的軟體打包起來,打包的檔案稱為 Docker Image
- Docker Registry:用來存放 Docker Image供 Docker下載使用,可以是公開的也可以是內部私用的
- Docker Hub:Docker 官方提供的 Docker Registry
常用指令:
docker search <Docker Image>
搜尋 Docker Image
docker pull <Docker Image>
下載 Docker Image
docker images
查看已下載過的 Docker Image
啟動指令:
docker run -p <對外port>:<預設port> -d
例
docker run -p 8080:80 -d nginx
用 nginx的 docker image以 Detach
的方式在主機 8080 port上提供服務
有 -d
指令執行後會回傳 Container ID,會將程式執行在「背景」,如果沒有加 -d
會將程式執行在「前景」
* 解決 Container啟動後就結束的問題:
Container被啟動後,會和一般的程式一樣,在作業系統中被視為一支執行中的程序 (Process),所以這個 Container就會像跑一支程式一樣跑完之後就會被結束掉。如果要順利可以使用的話,就需要在 Container裡啟用一個伺服器的程式(持續執行中的程式)讓 Container保持運行
docker rmi <Image名稱或 ID>
刪除 Docker Image
Docker Image是一層一層疊出來的,不同的 Docker Image可能有共用到同一層的部份,所以移除掉某個 Docker Image後所拿回來的硬碟空間不一定會和看到或所想的一樣
查看啟動過的 Container
docker ps
指令查看狀態
例:
docker run -p 8080:80 -d nginx
docker run -p 8080:80 nginx
分別啟動一個前景執行和一個背景執行的 nginx,前景執行的 nginx會在 terminal中顯示 nginx的訊息。這時候另開 terminal使用 docker ps
指令會看到兩個已啟動的 Container資訊
按下 Ctrl + C
會把前景執行的 nginx給中斷,這時候使用 docker ps
指令查看會只看到一個已啟動的 Container資訊
docker ps -a
中的 -a
選項會把所有已經啟動過的 Container都列出來(不論是不是在運行)。所以以上面的例子即會看兩筆 Container資訊,其中一個是正在運行另一個是中斷運行(看 status
欄位)
docker ps -l
中的 -l
選項會顯示最後一組建立的 Container資訊
停用和啟用 Container
docker start <Container ID>
docker stop <Container ID>
docker restart <Container ID>
restart會先停止再啟動
docker rm
移除 Container。如果確定狀態是 Exited
的 Container已經沒有再使用的話,要使用 docker rm
指令來移除(如 Container不是在停止狀態下移除會出現錯誤訊息)
Container不會在被停用之後就移除掉,所以使用 docker run
來新增 Container幾次後,用 docker ps -a
指令就可以看到有許多已經沒有在運行的 Container。
docker ps -s
查詢 Container佔用多少硬碟空間
詳細 Container資訊
docker inspect <Container ID>
詳細配置資訊
可以進設定輸出格式及範圍,例 docker inspect --format='{{json .State.Status}}' node-red-couchdb
一次作多個 Container
只要是可以用 Container ID進行操作的指令,都可以一次輸入多個 Container,包含 docker start
, docker stop
, docker rm
…等
例 docker start <Container ID> <Container ID> <Container ID>
搬移檔案
把檔案複製到 Container裡
docker cp <檔案來源路徑> <目的Container ID>:<目的路徑>
把檔案從 Container複製出來
docker cp <來源Container ID>:<檔案來源路徑> <目的路徑>
無論是運行中或停止中的 Container都可以進行操作
查看 Container使用資源(CPU、記憶體)
docker stats
查看全部 Container
docker stats <Container ID>
查看指定 Container
會以「即時」的方式呈現目前狀況資訊
查看 Container的即時 Log
當 Container是以 Detach模式(背景)執行時,沒有辦法在命令列上直接看到 Log資訊,這時就需要使用 docker logs
指令才能看到 Log資訊
docker logs <Container ID>
可以看到指定的 Container Log資訊
選項 --tail
可以只顯示數幾行的資訊,例:
docker logs <Container ID> --tail 2 76d1
選項 --since
可以只顯示倒數分鐘以前的資訊,例:
docker logs <Container ID> --since 2m 76d1
CH3 Docker Container的進階操作
Container 命名
--name
用來指定 Container名稱(沒有指定名稱時 Docker會自動隨機取名)
搭配 docker run docker run --name <Container名稱>
例
docker run --name nginx-hello -p 8080:80 -d nginx
docker start nginx-hello
因為 Container的名稱必須是唯一的,因此每次用 docker run 指令啟動 Container都必須指定不同的名稱
環境變數
-e
用來設定變數值
例 dockr run -e <變數名稱>=<變數值> -p <對外port>:<預設port> -d <Docker Image名稱>
mysql範例
$docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456789 -d mysql
$docker exec -it mysql mysql -p
Enter password:
略
docker run 與 docker create
docker create
需搭配 docker start
指令才會啟動
docker run
執行之後就會立即的運行
docker kill 與 docker stop
docker stop
:讓 Docker進入標準的關機程序;所有的程式會進入到各自的關機處理程序,等所有程式完成關機程序之後 Docker也進入自己的關機程序
docker kill
:強迫進行 Docker的關機動作
執行 Container內的程式或指令
適用情況:有一種 Container的用途是被拿來當作軟體的工具包
指令寫法:直接在 docker run
的指令最後面加上想要執行的指令
例,把本機資料夾 C:\downloads檔案清單列出來
dockr run -v C:\downloads:/home ubuntu /bin/ls -l /home
(先使用 -v
指令在本機外掛資料夾,並使用 ls工具用 -l
指令檢視)
自動移除、自動重新啟動
--rm
:Container停止後就會自動移除
例 docker run --rm -v C:\downloads:/home ubuntu /bin/ls -l /home
--restart
:讓 Container在不預期情況被停止時,依照 --restart
的設定方式決定要不要自動重新啟動 Container(預設是 no
)
設定值:
no
always
unless-stopped
:和always
一樣有服務中斷自動重啟的功能,但是重開機後就不重啟on-failure
:只在 Container的退出狀態代碼 (Exit Code)不是零 (Non-Zero)
進入 Container操作命令列
想要透過指令來操作 Container的話,只要能啟動 Container裡的 Shell程式就可以了,一般 Linux作業系統常用的 Shell程式是 bash這一支程式
錯誤指令:
docker run --rm --name nginx-cmd nginx /bin/bash
要使用 -it
(-i
和-t
的合併寫法)指令來進入能夠輸入指令(及能把執行結果送出來)的狀態
正確指令:
docker run -it --rm --name nginx-cmd nginx /bin/bash
docker exec
:可以對已經在運行中的 Container要求執行指令
範例
docker run --name nginx-cmd -d nginx
docker exec -it nginx-cmd /bin/bash
Container綁定 IP
-p
指定 Container所要綁定的 IP位址
Docker預設會把 Container綁定到主機的 0.0.0.0
對外服務的建議指令:
docker run -p <主機IP>:<主機port>:<Container port> -d <Docker Image>
例
docker run -p 192.168.1.1:80:80 -d nginx
docker network
傳統上會把伺服器和資料庫裝在同一個虛擬機器裡,在 Container上建議的做法是用 docker network
建立一個 Docker網路,再把這兩套軟體分別啟動各自獨立的 Container到同一個 Docker網路之中
例
docker network create <網路名稱>
docker run --name --net=<網路名稱>
除了使用--net
方式來連接多個 Container,也可以利用 Docker Compose工具來達到
Data Volume - docker run直接指定本機路徑
Container運行產生的資料是會隨著 Container的消滅而消失,並且 Docker Container是採用一種層疊的方式來新增資料,所以每次有新增資料時就會產生一層新資料層疊加上去,而頻繁的寫入資料會產生大量的資料層而快速的吃掉硬碟空間。
-v
:掛上外部的硬碟空間
指令如下:
docker run -v <外部資料夾或檔案路徑>:<Container內部資料夾或檔案路徑> -p <對外port>:<預設port> -d <Docker Image>
例 - 資料夾
docker run -v /var/www:/usr/share/nginx/html --name nginx-store -p 8080:80 -d nginx
例 - 設定檔
docker run -v /home/ayubiz/nginx.conf:/etc/nginx/nginx.conf -v /var/www:/usr/share/ginx/html --name nginx-store -p 8080:80 -d nginx
Data Volume - data volumn create
使用 dota volumn create
建立 Data Volumn可以更方便的操作和管理 Data Volumn
例
$docker volumn create nginx-html
$docker volumn ls
略
$docker run -v nginx-html:/usr/share/nginx/html --name nginx-vol -p 8080:80 -d nginx
如果要讓另一個 Container也使用相同的 Data Volumn的話,只要使用相同的 Data Volumn名稱掛載即可
$docker run -v nginx-html:/usr/share/nginx/html --name nginx-vol3 -p 8081:80 -d nginx
不過多個 Container共用同一個 Data Volumn時要注意避免共同更新同一個檔案,以免造成資料的混亂或錯誤。
CH4 各種自製 Docker Image的方法
從運行中的 Container產生映像檔
docker commit <Container ID> <產出的 Docker Image名稱>
例
docker pull nginx
docker run --name nginx-hello -p 8080:80 -d nginx
docker cp index.html nginx-hello:/usr/share/nginx/html
docker commit nginx-hello nginx-commit
在此例中即使先執行了 docker stop
中止後仍然是可以執行 docker commit
指令的,不過掛載在 Container上的儲空間是不會被存進到新產生的 Image
Dockerfile的 Build指令
Dockerfile可以把他看成是一個腳本檔來看,他被用來明確的告訴 docker build指令在產生新 Image的時候所需要用到的資訊和步驟
FROM
指定要下載的 Image檔名稱
例:
FROM node:14-alpine
ENV
設定環境變數
例:
ENV NODE_ENV=$deploy_env
RUN
執行指令
EXPOSE
指定 Container啟用的 port
例:
EXPOSE 80 443
CMD
Container啟動完成後要執行的指令。當同一個 Dockerfile裡有多個 CMD
指令時,只有最後一個 CMD
指令會有作用
例:
CMD ["nginx", "-g", "damon off;"]
ENTRYPOINT
Container啟動完成後要執行的指令,功能和 CMD
類似,差異在於其不能在 docker run
後面加入的指令來蓋掉 ENTRYPOINT
指令所要求的啟動方式。也就是說他一定會被執行,且可以在 docker run
後攜帶參數使用。
當同一個 Dockerfile裡有多個 ENTRYPOINT
指令時,只有最後一個 ENTRYPOINT
指令會有作用。他可以和 CMD
搭配使用
WORKDIR
指定執行指令的資料夾位置
COPY
複製檔案到 Container當中。指令:COPY <來源檔路徑和檔名> <Container裡的完整路徑和檔名>
另外還有一個指令 ADD
與 COPY
相似,不過 ADD
是將檔案放到 Image裡,主要的差異是在 ADD
多了可以用網址指定來源檔和可以自動解開 tar壓縮檔的功能;官方比較建議使用 COPY
指令。
LABEL
將 Image檔的作者、版本、描述及其他自訂資料儲存到新產生的 Image檔,而存入的資訊可透過 docker image inspect
指令查看 Labels
欄位
指令:LABEL <欄位名稱>:"<欄位值>" <欄位名稱>:"<欄位值>" <欄位名稱>:"<欄位值>" ...
USER
大部份的 Image檔都會使用最高權限的 root做為預設的使用者帳號,如果不想用 root作預設的使用者的話,可以用 USER
指令指定帳號
VOLUME
提供 Data Volume的掛載
指令 VOLUME ["<掛載點的資料夾路徑>", "<掛載點的資料夾路徑>" ...]
或 VOLUME <掛載點的資料夾路徑> <掛載點的資料夾路徑> ...
ARG
可以讓 docker build
指令利用 --build-arg
選項傳入參數到 Dockerfile裡
指令 ARG <參數名稱>
或 ARG <參數名稱>=<預設值>
匯入/匯出 Image檔
匯出指令: docker save -o <匯出的檔案名稱.tar> <要匯出的 Image名稱>:<版本>
docker save
匯出的檔案格式為 tar壓縮檔,名稱可加上 .tar
也可不加
匯入指令:docker load -i <之前匯出的Image.tar>
或docker load < <之前匯出的Image.tar>
用 Container匯出 Image
這種方式不是將運行中的 Container整個匯出,只是將 Container內部使用中的檔案系統匯出
匯出指令 docker export -o <匯出的檔案名稱.tar> <Container ID>
或 docker export <Container ID> > <匯出的檔案名稱.tar>
匯入指令 docker import <匯入的檔案名稱與路徑> <映像檔名稱:版本標籤>
CH5 利用 Docker Compose管理多個 Container
Docker和 Docker Compose是兩個各自獨立的程式,Docker Compose需要額外安裝
主要功能和使用情境:
- 管理多個 Container
- 自動化(透過將 docker run的設定放進 docker-compose.yml的方式達到更彈性與自動化的部署)
docker-compose.yml文件指令
(指令太多了一時間筆記不完,沒實際操作也吸收不了,所以就先跳過)
頂層指令:
version
services
volumes
networks
configs
scerets
常用指令
docker-compose
的指令幾乎是和 docker
的指令相同,不過 docker-compose
指令的操作都是基於 docker-compose.yml
的內容,所以也就可以更容易的進行批次操作。另外,docker-compose
指令多是以 docker-compose.yml
檔案裡的 service名稱來做為參數使用,不直接給 Container的名稱
-f
選項指定 docker-compose.yml檔案路徑和名稱,例:
docker-compose -f ~/node-red/docker-compose.yml config -q
docker-compose config
:檢視檔案內容
docker-compose build
:使用 Dockerfile產生 Docker Image
docker-compose pull <Image>
或 docker-compose pull
:指定取得一個或多個 Image( 如未指定則下載所有 docker-compose.yml檔所有指定的 Image檔),例:
docker-compose pull node-red db
start
, stop
, restart
, pause
, unpause
, kill
:對指定或者全部 Container進行操作
例:
# 停止指定 Container
docker-compose stop node-red db
# 停止全部 Container
docker-compose stop
docker-compose rm
:和 docker rm
指令相同,可以用來移除已經停止運行的 Container
docker-compose run
:和 docker run
指令相同,可以用來啟動 Container
docker-compose up
:最常使用的指令,用來啟動所有的服務
docker-compose up
的常用選項:
-d
: 在背景模式下執行--no-recreate
: 不需要重建每個服務所使用的 Container--force-recreate
:無論 docker-compose.yml或 Image檔案有無調整或改變,都強迫執行重新建立服務所使用的 Container的動作