捐血一袋救人一命

江蘇拙政園

江蘇 拙政園

全家福

日本 和歌山城

賞楓之旅

千燈 夕照

水鄉千燈

蘆洲 微風運河

破曉時分

2023年11月2日 星期四

容器 Container 簡介

容器 Container 簡介
  • 這裡介紹都使用容器這個名稱,而不是使用 Docker
  • 因為實踐容器技術的系統有很多種,不是只有 Docker
  • 但不可否認的是,Docker 確實是業界標準!畢竟它最早開始實作容器技術!

容器簡介

甚麼是容器(Container),為什麼它發展比虛擬系統還快,有甚麼優點?

  • 容器是一種應用程式系統打包、隔離執行環境、管理運行的技術。
  • 隔離的環境包括CPU、Memory、Disk I/O、網路頻寬等資源,確保每個運行中的容器,不會互相干擾破壞,也不會影響 Container Host
  • 容器可以快速啟動執行!6
  • 虛擬系統跟實體系統一樣,啟動需要經過開機、測試硬體環境、載入作業系統、驅動程式等等…所以需要花大量的時間。
  • 每個虛擬系統需要佔用大量的記憶體給作業系統以及磁碟空間
  • 容器本身是運行在已經啟動的系統上(不管是實體或是虛擬),它相當於你平常運行應用程式差不多!
  • 容器其實跟 Portable Apps 很像!只是以往要打包 Portable Apps 需要購買軟體授權,例如:VMware ThinAppCameyo,當你安裝好 Portable Apps 建置系統之後,它會先掃描你的軟硬體環境,將這些資訊都紀錄下來,然後你安裝付費的授權軟體、啟用授權軟體,完成安裝之後,ThinApp 會再次掃描整個系統,確認那些地方被修改異動,然後將這些資訊打包成一個 Portable App,讓你可以將這個打包的應用程式搬移到任何電腦上運行!
  • 容器技術不只是打包應用軟體、隔離執行環境資源,還提供執行管理相關的工具,讓應用程式散佈運行更方便!
    比較項目 容器 虛擬系統 說明
    執行啟動效率 虛擬系統需要經過開機啟動程序
    使用資源量 虛擬系統需要使用大量的 CPU、RAM、Disk 給作業系統
    費用成本 授權費0 授權費高 需要進階管理虛擬系統,需要支付高額的授權費用
    運行作業系統平台 需一致 不須一致 Linux 平台上,只能運行 Linux 架構的容器,不能運行 Windows 架構的容器

容器技術的四個物件:Image, Container, Volume, Network

  • Image:Base Image + 你開發的應用程式/或是你要運行的系統 + 設定檔案 + 資料檔案等等,打包成一個新的 Image
    • Image 可以匯出成 tarball 格式(早在磁帶備份時期就開始使用的資料檔案封存格式,壓縮性低)檔案
    • Image 可以上傳(push),到公有或私有 Repository 儲存伺服器上
      • 公有 Repository 有很多,最著名就是 Docker Hub,Redhat Linux 也有自家 Repository,Google GCP 也有
      • 建立私有 Repository
  • Container:包含了 Image 以及執行環境狀態紀錄;預設下,Container停止時,Container 只是停止運行,但是網路、磁碟等資源仍然是占用的狀態。
  • Volume:方便管理的磁碟管理
    • 可以讓你將 Host Volume 掛載到 Container 裡面,供Container 的應用程式系統讀寫;也因為是 Host Volume,你可以很方便地透過 Host 管理
    • 可以透過 Host 掛載網路磁碟服務(網路芳鄰SMB/CIFS/SambaNFSiSCSI)、後,再掛載到 Container。
      enter image description here
    • Network:容器的網路運行在虛擬的隔離網路之中,存取只能透過Container 技術,意即不容易透過網路入侵或攻擊外部,且虛擬的網路環境,可以很容易在其他 Host 進行部屬(不使用固定 IP)

一些常用的 Docker 指令

查詢 Docker 指令參數說明

指令 用途
docker --help 查詢所有 Docker 指令及概要說明
docker [command] --help 查詢 Docker Command 進一步的詳細說明

如何管理 Images

指令 用途
docker pull [image_name:image_tag] 從 Repository 下載 Image
docker images [image_name:image_tag] 查看本機目前已經下載的 Images
docker push [repo_host/image_name:image_tag] 將 Image 上傳到 Repository
docker rmi [image_name:image_tag] 刪除本機的 Image
docker save [image_name:image_tag] > file_name.tar 將本機 Image 匯出存成 tarball 檔案
cat file_name.tar | docker load 從 tarball 檔案匯入本機
docker history [image_name:image_tag] 查看當初 image 建立的指令
docker inspect [image_name:image_tag] 查看JSON格式的 Image 資訊
docker commit [container_id 或 container_name] [new_image_name:new_image_tag] 將目前Container 內的檔案狀況寫成新的Image
docker tag [image_name:image_tag] 設定/更改 Image 名稱及 Image Tag

docker push 要怎麼知道要把 Image push 到哪個 repository?

要透過 docker tag 將 image 設成 repo_server _fqdn/image_name:image_tag
例如:

docker tag newepay:20231010 repo.funday.asia/newebpay:latest
docker push repo.funday.asia/newebpay:latest

如何運行容器、停止容器、重新啟動容器、刪除容器

指令 用途
docker run [Options] [image_name:image_tag] [Command] [Args for Command] 以 Image 運行一個新的 Container
docker exec [Options] [container_id 或 container_name] [Command] [Args for Command] 在一個運行中的 Container 執行指定的命令
docker attach [container_id 或 container_name] 將Container 的標準輸出、輸入、錯誤,連接到Host。通常用於容器除錯。當你Ctrl-C中斷程式時,會連帶導致容器運行中止!要脫離Attach Mode,請按Ctrl-PQ
docker stop [container_id 或 container_name] 停止運行指定的容器
docker start [container_id 或 container_name] 啟動已停止運行指定的容器
docker restart [container_id 或 container_name] 重新啟動證在執行的容器
docker rm [container_id 或 container_name] 刪除已停止的容器

如何觀察容器內運行的程式

指令 用途
docker top [container_id 或 container_name] 查看容器內運行的程式
docker inspect [container_id 或 container_name] 顯示 JSON 格式的 Container 運行狀態資訊

如何將容器內的資料取出?如何將檔案放入容器中

指令 用途
docker cp [container_id 或 container_name]:/path/to/[file] /host/path/to/[file] 將容器內的檔案複製到 Host 指定路徑檔名
docker cp /host/path/to/[file] [container_id 或 container_name]:/path/to/file 將Host 指定路徑檔案複製到 Container 內的指定路徑檔名

如何觀察容器內那些檔案被異動

指令 用途
docker diff [container_id 或 container_name] 條列容器內部有異動或新增的目錄及檔案,C 表示 Change,A 表示 Append

如何觀察容器內程式運行的紀錄

指令 用途
docker logs [container_id 或 container_name] 查看容器內程式產生的 Log資訊

如何遷移影像、容器、資料檔案

一種方式是把 Image Push 到 Repository Server,然後再從其他 Host Pull Image 下來執行
另一種方式,就是匯出 Image,然後傳送到 Remote Server 再匯入運行


如何製作容器影像

  • 選取一個可信任的 Base Image
    • 請選擇 docker Official Image 或是 Verified Publisher 提供的 Image
  • 熟悉 Dockerfile 指令及用途

如何讓容器重新開機就自動運行

Docker 的開機後自動運行依賴 docker daemon 來管理

–restart 參數值 用途說明
no default值,當容器狀態 exit 時,不要重新啟動
on-failure 當容器發生異常結束時,自動重啟
on-failure:n 當容器發生異常結束時,最多重啟 n次
always 永遠自動重啟容器,即使在重新開機之前,容器就已經停止,開機啟動後,仍要自動執行容器
unless-stopped 如果在重新開機之前,容器就已經停止,就不會自動重啟

–restart 參數不可以與 --rm 參數同時使用!

Podman 的開機後自動運行依賴 systemd 來管理

podman generate systemd [containber_id 或 container_name] > /usr/lib/systemd/system/myweb.service
systemctl enable myweb
systemctl status myweb

參考資料:

  • 如何自行建立基底 Image from Docker Official Website
    • 你可以利用別人建立好的基底,快速開發你的應用程式環境,也可以自己閉門造車或是打造你自己完全控制的環境。

2023年11月1日 星期三

以非 root 身分運行 Docker

以非 root 身分運行 Docker

如何讓非 root 使用者也可以執行 docker

以下指令請以非 root 身分執行

if [ $(grep docker /etc/group | wc -l) -eq 1 ]; then echo "group exists."; else sudo groupadd docker; fi
sudo usermod -aG docker $USER;
newgrp docker;
sudo chown "$USER":"$USER" /home/"$USER"/.docker -R;
sudo chmod g+rwx "$HOME/.docker" -R;

參考資料:
Run the Docker daemon as a non-root user(Rootless mode)

建立 Docker Image 並執行

建立 Docker Image 並執行

Dockerfile 中 ENTRYPOINT 與 CMD 的差異

建立 power.sh Bash Shell Script

  1. 此 Shell Script 透過 curl 程式,抓取政府資料開放平台台電供電資訊 JSON 格式資料
  2. 然後透過 jq 程式,解析、擷取特定 JSON 資料
  3. 最後顯示台電供電資訊
#!/bin/bash
#取得 JSON 資料並解析
json_data=$(curl -s -k https://data.taipower.com.tw/opendata/apply/file/d006020/001.json)

yday_maxi_sply_capacity=$(echo "$json_data" | jq -r '.records[2].yday_maxi_sply_capacity')
fore_maxi_sply_capacity=$(echo "$json_data" | jq -r '.records[1].fore_maxi_sply_capacity')
yday_peak_dema_load=$(echo "$json_data" | jq -r '.records[2].yday_peak_dema_load')
fore_peak_dema_load=$(echo "$json_data" | jq -r '.records[1].fore_peak_dema_load')
publish_time=$(echo "$json_data" | jq -r '.records[1].publish_time')

#比較並顯示結果
fore_maxi_sply_capacity=${fore_maxi_sply_capacity%.*}
yday_maxi_sply_capacity=${yday_maxi_sply_capacity%.*}
fore_peak_dema_load=${fore_peak_dema_load%.*}
yday_peak_dema_load=${yday_peak_dema_load%.*}

if [ $fore_maxi_sply_capacity -gt $yday_maxi_sply_capacity ]; then
    result="預估供電能力有增加"
else
    result="預估供電能力有下降"
fi

echo "資料時間: ${publish_time}"

echo "昨日最大供電能力: " $yday_maxi_sply_capacity
echo "預估今日最大供電能力: " $fore_maxi_sply_capacity
echo "比較結果: " "$result"

echo "昨日最大用電量: " $yday_peak_dema_load
echo "預估今日最大用電量: " $fore_peak_dema_load

設定 power.sh Bash Shell Script 可以執行

chmod +x power.sh

建立 Dockerfile,內容如下:

FROM	rockylinux:8.7
RUN	dnf update -y
RUN	dnf install -y curl
RUN	dnf install -y jq
COPY	power.sh /usr/bin/power.sh
CMD	/usr/bin/power.sh

建立 power:1 Docker Image

docker build -t power:1 .

修改 Dockerfile,內容如下:

FROM	rockylinux:8.7
RUN	dnf update -y
RUN	dnf install -y curl
RUN	dnf install -y jq
COPY	power.sh /usr/bin/power.sh
WORKDIR           /usr/bin
ENTRYPOINT     ["power.sh"]

建立 power:2 Docker Image

docker build -t power:2 .

分別運行這兩個 Images

兩個 Container 都可以如預期般的執行

docker run -it --name p1 power:1
docker run -it --name p2 power:2

刪除 p1 & p2 Containers

docker rm p1 p2

這次 run Container 時,要求執行 Bash Shell

docker run -it --name p1 power:1 bash
exit
docker run -it --name p2 power:2 bash

結果 p1 進入了 Container 裡面,並執行了 Bash Shell;而 p2 完全忽略要求執行的 Bash Shell

enter image description here