Skip to main content

「Docker這樣學才有趣」讀書筆記

· 20 min read
Adam You

前言

這是我讀了「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授權)的開發原始碼專案

https://github.com/moby/moby

↑ 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裡的完整路徑和檔名>

另外還有一個指令 ADDCOPY相似,不過 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的動作