Docker 筆記
雖然之前有聽過一堂關於 Docker 的課程,但一直沒有實際應用。
這次修了一堂課,並指定要用 Docker 架點東西,於是有了這份筆記。
Docker 簡介
一個輕量的虛擬化技術。
有時候我們只是要建立一個 "服務",但單為這個服務開一個 VM 會非常耗資源。
(撇開儲存空間,啟動一個 VM 再怎麼說也是要不少 Ram 以及執行緒去操作 Hypervisor)
這時候 Docker 這樣的服務就會很有用,我覺得你也可以把它想像成 Android 手機大家常常討論的
" APP 多開程式 "。
想想看,在以前,一隻手機只能登一個 Line 帳號。
如果我想要同時操作兩個帳號,就必須要有兩支手機。(撇開重簽 APK)
今天有了多開程式,簡化了所需的資源(手機),也省去了很多步驟 (操作另一隻手機,重裝 APP ... 等)
即使你用 PC 好了,PC 多開手機模擬器
但肯定還是沒有一個模擬器裡面同時操作兩個 APP 來的方便。
Docker 就是像這樣的存在,故在現今也有很高的利用價值。
Docker 行為
- 建立 ( docker container create )
- 執行 ( docker container start )
- 進入或修改內容 ( docker container attach, docker container exec… )
- 暫停 ( docker container pause )
- 停止 ( docker container stop )
- 移除 ( docker container rm )
Docker 指令
- 取得 Image :
docker image pull [Image Name]
- 建立 Container :
docker container create [options] [Image Name] [command (opt)]
- --name, --interactive, --tty, --publish, --volume, --workdir
- 如果不是用 create 而是用 run,會是建立容器並執行
- 執行時可以加參數限制資源 :
--cpuset-cpus=1
- 執行 Container :
docker container start [options] [Container Name]
- --attach : Attach STDOUT/STDERR and forward signals
- --interactive : Attach container’s STDIN
- 查詢 Container :
docker container ls [options]
- --all, --quiet, --size
- 舊版本是
docker container ps
,或是簡化成docker ps
,都能用- ref : here
- 查看 Container 執行結果 :
docker container logs [options] [Container Name]
- --follow, --time
- 進入 執行中 Container :
docker container attach [Container Name]
- 進入 執行中 Container :
docker container exec [options] [Container Name] [command (opt)]
- Ver 1.3+
- --env, --interactive, --tty, --user, --workdir
- 進入 執行中 Container :
以下是一些操作指令
- 交換資料 :
docker container cp [Local path] [Container Name:Path]
- 上述是 Local 複製到 Container 內,反過來的話兩個參數對調即可。
- 檢視設定 :
docker container inspect [Container Name]
- 更新設定則使用 update
- Top :
docker container top [Container Name]
- 類似 Linux 的 top
- Status :
docker container status [options]
- --all
- Diff :
docker container diff [Container Name]
- 暫停 :
docker container pause [Container Name]
- 停止 :
docker container stop [options] [Container Name]
- --time
- 移除已停止的 Container :
docker container rm [Container Name]
- 強制移除 : -f,但不建議使用。
- 更改標籤 :
docker container rename [Container Name] [New Name]
Image 操作
- 匯出 (備份) :
docker container export [Container Name] [-o new_name]
- 匯入 Container 的備份成 Image :
docker image import [filename] [New_Container_Name[:tag]]
- 匯入網路上的 Container backup 成 Image : ``docker image import [url] [New_Container_Name[:tag]]
在找 image 時可能會遇到的操作
搜尋 :
docker search [options] [Keyword]
下載 :
docker pull [Image Name]
查看 local 使用 ls,刪除已下載的用 rm,查看細節用 inspect (前面已介紹過)
紀錄 : ``docker image history [Image Name]
現有 Container 製作成 Image : ``docker container commit [options] [Container Name] [Image Name]
- --author, --change, --message, --pause
透過 Dockerfile build Image :
docker image build [OPTIONS] PATH | URL |
Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE:
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
push 到 Registry :
docker image push [Image_Name[:標籤]]
儲存 Image 為檔案 :
docker image save [Image_Name[:tag]] > [File_Name]
- 和 container 的 export 差不多
從檔案載入 Image :
docker image load [Image_Name[:tag]] < [File_Name]
- 改箭頭而已
流程舉例
1 | docker image pull bash |
1 | # 建立 |
Image 製作
使用 dockerfile 製作,優點 :
- 純文字,檔案小,分享快
- 版本管理
- 應該使用一個空目錄來裝載 dockerfile
常見語法
- 註解 : #
- Image Base :
FROM image[:tag]
- 標籤 :
LABEL key=value
- 定義變數 :
ENV name=value
,ARG name=value
- 新增檔案 :
ADD src dest
,COPY src dest
- 執行指令 :
RUN command para1 para2
, CMD, ENTRYPOINT - 工作目錄 :
WORKDIR /path/../..
- 指定使用者 :
USER user[:group]
- 對外 Listen Port :
EXPOSE port [/protocol]
- 僅是宣告用途,run 的時候要自己加參數去做對應。
- 呈上,
-p <host port>:<container port>
- 掛載實體位置 :
VOLUME [path]
實際運行與架設
環境 : Ubuntu 20.04, on AWS Lightsial.
- 在 AWS Lightsial 給的 VM 中,預設的 account 叫做 ubuntu,直接可以免密碼做 sudo。
如果仍想要切 root 的 account,可以執行sudo bash
- 如果想要用 Local Terminal 做 ssh,可以先把 Local 的 id_rsa.pub 內的內容複製到 VM 中的 authorized_keys 裡面。
在 Ubuntu 20.04 安裝 Docker
跟著跑就好。
1 | sudo apt update |
然後可以開始跑 Hello-world 程式docker run hello-world
但是高機率會遇到一個錯誤訊息 :
1 | docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/create: dial unix /var/run/docker.sock: connect: permission denied. |
解法 :
1 | sudo groupadd docker |
之後建議先做 logout
,然後重新登入,這樣才會生效。
(若仍然沒效可以考慮直接 sudo chmod 777 /var/run/docker.sock)
以上都做完之後,試著跑跑看吧。docker run hello-world
有看到出現這段,基本上應該就沒問題了。
1 | Hello from Docker! |
安裝 Apache 的 Docker 包
1 | docker search httpd |
為了練習使用 dockfile,透過寫一個 dockfile 來建立 image
1 | FROM httpd:latest |
搭配使用的 build 指令 :
1 | docker build -t WebServer/apache_proj . |
先用 docker images
確認一下
搭配使用的 run 的指令 :
1 | sudo docker run -itd --name apache_proj -p 8888:80 -v ~/dk_workenv/html/:/usr/local/apache2/htdocs/ webserver/apache_proj |
用 docker ps
看一下執行中的 Container
然後我很高興的跑去瀏覽器試試 http://ip:8888
但是完全連不上。
先做 localhost 檢查 curl localhost:8080
有看到東西。至少我的 volume 沒有出問題。
然後先用 docker container logs apache_proj
查看一下目前 log
再用 curl localhost:8080
去連接,再 logs
一次,有看到關鍵回饋 :
1 | [10/Oct/2020:17:04:02 +0000] "GET / HTTP/1.1" 200 5 |
感覺都沒問題啊。
我可以從 VM 內去連接 Container 內的 80 port,然後從 VM 的 8888 出去。
... 那為何外界無法接到我的 8888 port ?
於是跟著這個想法,我去了 Lightsail 的控制台 ... 默默的把 TCP 8888 port 打開 ...
... 成功了。
(請各位如果是用 VPS,記得去把 port 打開 ...。)
Docker-Compose
Docker-Compose 的用途是用來管理多個 image 成一個執行體
例如 wordpress + mySQL 服務一起搭建,我只需要寫好 docker-compose.yml
然後下個啟動指令,兩個 image 都能從 container 形式啟動。
並且, docker-compose 還可以放很多參數 (docker container run [...] 所指定的參數)
也能將 Dockerfile 整合進來,可以說是非常方便,也很推薦使用。
第一次摸索時很排斥參數一大堆又不知道怎麼去配合,下面做點有使用和沒使用的情境 :
- 假設我沒使用 docker-compose :
- 使用指令方式將 image 啟動成 container (或是我們透過 Dockerfile,同樣效力)
- 舉例 :
docker container create -it --name apache_proj httpd
- 或是透過 Dockerfile,寫好 Dockerfile 後執行
docker build -t my_webserver/apache_proj .
- 舉例 :
- 啟動成 container 之後,使用
sudo docker run -itd --name apache_proj -p 8888:80 -v ~/dk_workenv/html/:/usr/local/apache2/htdocs/ my_webserver/apache_proj
- 使用指令方式將 image 啟動成 container (或是我們透過 Dockerfile,同樣效力)
沒錯,就是這麼長。
- 假設我有使用 docker-compose :
- 寫好 Dockerfile,放在當前目錄 (請參考前一個段落,有範例)
- 寫好一個 docker-compose.yml,範例在下面。
- 我們可以觀察到,我把 docker run 所需要的參數都放進去 docker-compose 檔案裡面了。
- 然後跑
docker-compose up -d
這樣就好了。
1 | version: '3.8' |
變得簡潔很多,很有條理,不需要自己一直重複打那些參數做一樣的事情。
那,如果,今天我已經有做好 image,只是想透過 docker-compose 執行 ?
(也就是我不想用 docker run)
docker-compose up -d --no-build
-d
代表 detach,若你沒加的話,你當前的 terminal 就會直接 print 出 container 執行中的 log。
如果加了,他就會在 background 執行,你可以繼續用當前的 terminal 繼續做其他事。--no-build
就代表了不重新 build image。
使用方式差不多是這樣。
Ref
A tutorial about Docker
Docker - 第十三章 | 安裝Apache Server
利用 Dockfile、Docker Compose 建立 LAMP 環境 (PHP、Apache、MySQL)