捐血一袋救人一命

江蘇拙政園

江蘇 拙政園

全家福

日本 和歌山城

賞楓之旅

千燈 夕照

水鄉千燈

蘆洲 微風運河

破曉時分

顯示具有 docker 標籤的文章。 顯示所有文章
顯示具有 docker 標籤的文章。 顯示所有文章

2024年7月18日 星期四

Docker Engine API

Docker Engine API

Docker 的架構

  • 下圖是 Docker 官方的架構圖
  • 由圖可知,Docker Client 與 Docker Host 是可以分開的
  • 而我們一般運行 Docker,Client & Host 是同一台伺服器
    image.png
  • Docker Engine 提供了 Web API,讓你可以使用慣用的程式語言來控制 Docker Engine,甚至 Docker Container Apps 的數量(Scale Up/Down)
  • 另外,Docker Engine 也提供了 SDK for Go & Python,熟悉這兩種語言的人,可以直接使用 SDK
  • Docker Engine API 是 RESTful API,你可以很輕鬆地使用 wget, curl, powershell, 或是你慣用的程式語言來存取它。
  • 要使用 Docker Engine API 之前,必須先知道你的 Docker Engine 版本所使用的 API 版本

查詢 Docker API 版本可以使用以下命令

docker version

image.png

啟用 Docker Engine API

Docker Engine API 預設是沒有啟動的,必須自行設定,設定步驟如下

  1. 開啟遠端 Docker Host 上的 Docker Service 設定檔
# 以 systemctl 讀取服務設定
# 第一行是設定檔路徑檔名
# 將第一行的註解符號去除掉,得到完整路徑檔名
# 存入環境變數
DOCKER_SERVICE_CONF_FILE=$(systemctl cat docker.service | head -n 1 | sed 's/^#\s//g')
vi ${DOCKER_SERVICE_CONF_FILE}

# vi /usr/lib/systemd/system/docker.service
  1. 修改其中 ExecStart 的命令,增加 -H tcp://0.0.0.0:2375 並存檔。
    image.png

  2. 然後讓 systemd 重新載入 Daemon 相關設定檔,然後重新啟動 Docker

# 讓 systemd 重新載入 Daemon 設定檔
sudo systemctl daemon-reload
# 重新啟動 Docker Daemon
sudo systemctl restart docker
# 檢查 Docker Service 狀態
sudo systemctl status docker

如果有正常啟動 docker daemon 會看到如下圖

image.png

  1. 檢查 Docker 是否有監聽 2375 Port
sudo lsof -i -P -n | grep dockerd

image.png

sudo ss -tulpn | grep dockerd

image.png

以上就完成了啟用 Docker Engine API


Docker Engine API v1.43 簡單列舉容器相關操作

查詢 Container 資訊

Method: GET
http://{docker_host_ip}:2375/containers/json

參數 說明
all boolean,預設值為 false/0,表示只回傳正在運行的容器資訊;all=true/1,表示回傳所有容器資訊;注意這裡數值的布林值,與Python相同,只有0代表 false,其他數值,不管正負,都代表true
limit integer,回傳最近幾個Container的資訊,包含沒有在運行的容器
size boolean,預設值為 false,回傳資訊增加容器大小
filters string,設定篩選容器的條件

可用的 filters

參數 說明
ancestor 指定 “ancestor”: [“image_name”:“image_tag”]
before 指定 container_id 或 container_name之前的容器
expose 指定 expose port
exited 指定 container exit code
health 指定狀態:starting, healthy, unhealthy, none
id 指定 Container ID
isolation 指定隔離狀態:default, process, hyperv;Windows Daemon Only
label 指定 {“label”:[“key”]} 或是 {“label”:[“key=value”]}
name 指定Container Name
network 指定 network_id 或 network_name
publish 指定 port/proto 或 startport-endport/proto
since 指定 container_id 或 container_name之後的容器
status 指定特定狀態的容器:created, restarting, running, removing, paused, exited, dead
volume 指定volume_name 或 volume_id

範例:

curl http://192.168.13.161:2375/containers/json?all=1
curl http://192.168.13.161:2375/v1.43/containers/json?filters={"ancestor": ["nginx:latest"]}
curl http://192.168.13.161:2375/containers/json?filters={"label":["CallFrom=Powershell"]}

查詢指定的 Container 資訊

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/json

查看 Container 內部運行的程式

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/top

查看 Container 運行的 Log

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/logs

查看 Container 內部被異動的檔案/目錄

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/changes

匯出 Container 並下載

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/export

持續回傳容器運行資源狀態(JSON)

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/stats

建立容器(注意:容器只有建立,並沒有運行)

Method: POST

http://{docker_host_ip}:2375/container/create
網址參數 說明
name string,必須符合正規式 ^/?[a-zA-Z0-9][a-zA-Z0-9_.-]+$

Header請指定 “Content-Type: application/json”

Body JSON 簡單列舉參數如下

參數名稱 說明
Env Array of Strings,指定環境變數及值
Cmd Array of Strings,指定容器啟動時,要執行的命令
Image string,指定容器要使用的 Image Name 以及 Tag
Volumes 指定掛載的磁碟
WorkingDir 指定命令要在哪個目錄下運行
Labels 指定 Key/Value 的 Metadata
HostConfig 設定網路相關資訊,例如:Port Mapping

範例:

使用 bash shell curl 建立 Container

curl -X POST -H "Content-Type: application/json" \
-d '{"Image": "nginx:latest", "ExposedPorts": { "80/tcp": {} }, "HostConfig": { "PortBindings": { "80/tcp": [{ "HostIp": "", "HostPort": "9001" }] } } }' \
http://192.168.213.214:2375/containers/create

使用 Powershell 跑迴圈,建立三個 Container:web01, web02, web03,分別使用 Port 9001, 9002, 9003,並啟動這三個Container

$head = @{ 'Content-Type' = 'application/json' }

$Port = 9000
For($i=1; $i -le 3; $i++){
    $Port++
    $json  = "{""Image"": ""nginx:latest"", "
    $json += """ExposedPorts"": { ""80/tcp"": {} }, "
    $json += """HostConfig"": { ""PortBindings"": { ""80/tcp"": [{ ""HostIp"": ""0.0.0.0"", ""HostPort"": ""$Port"" }] } }, "
    $json += """Labels"" : {""CallFrom"":""Powershell""} }"

    # Create Container
    Invoke-RestMethod -Method POST -Uri ("http://192.168.13.161:2375/containers/create?name=web{0:d2}" -f $i) -Headers $head -Body $json
    # Start Container
    Invoke-RestMethod -Method POST -Uri ("http://192.168.13.161:2375/containers/web{0:d2}/start" -f $i) -Headers $head
}

啟動執行容器(Start)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/start

停止運行容器(Stop)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/stop

重新啟動執行容器(Restart)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/restart

傳送 POSIX signal 給容器(Kill)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/kill?signal=[SIGNAL_STRING | SIGNAL_CODE]

變更容器名稱(Rename)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/rename?name=[new_container_name]

刪除容器名稱(Remove)

Method: DELETE

http://{docker_host_ip}:2375/containers/[container_id | container_name]

以上,當你使用錯誤的 Method 時,會顯示 page not found 錯誤訊息

image.png

參考資料

Configure remote access for Docker daemon
Docker Engine API (1.43)
Docker Engine API version history
Develop with Docker Engine SDKs

docker config

docker config

  • 這個命令是用在 Docker Swarm 環境下
  • 你可以將你的應用程式容器需要的靜態檔案/設定檔,透過 docker config create 存到 Manager Node 上。
  • 當你的應用程式容器在 Worker Nodes 上部署運行時,可以將這些 config 檔案掛載到容器之中
  • 它跟 Volume 的差異,在於 Volume 的掛載是無法跨 Nodes,除非每個 Nodes 都去掛載網路磁碟(smb/nfs/…)

指令表

指令 Description 說明
docker config create Create a config from a file or STDIN 從 STDIN 或是應用程式設定檔來建立 config
docker config inspect Display detailed information on one or more configs 顯示 config 的詳細資訊(其中包含檔案被base64編碼的內容)
docker config ls List configs 條列 Manager Node 上的 config
docker config rm Remove one or more configs 刪除指定的 config

用實例離說明:

部署簡單的 php 程式到 Worker Node web

  1. 建立簡單的 php 程式檔案作為首頁 index.php,用來驗證部署結果
<?php
// 獲取伺服器的 IP 地址
$server_ip = $_SERVER['SERVER_ADDR'];

// 顯示在網頁上
echo "伺服器的 IP 地址是: " . $server_ip;

phpinfo()
?>
  1. 建立 apache 虛擬主機設定檔 ~/000-default.conf
<VirtualHost *:80>
    ServerAdmin webmaster@official.company.com
    ServerName official.company.com
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
  1. 以 apache 虛擬主機設定檔 000-default.conf,在 Docker Swarm Manager Node 上,建立 config
docker config create apache_vhost ./000-default.conf
  1. 列出 config,確認一下
docker config ls

image

  1. 檢查一下 apache vhost config 詳細資訊,你會發現,設定檔內容以 base64 編碼,存在 Data 中
docker config inspect apache_vhost

image

  1. 驗證一下apache_vhost config內容
docker config inspect apache_vhost | jq -r '.[0].Spec.Data' | base64 --decode

image

  1. 驗證一下 index.php config內容
docker config inspect official_homepage | jq -r '.[0].Spec.Data' | base64 --decode

image

  1. 編寫 docker-compose.yml
version: '3.8'

services:
  php_apache:
    image: php:7.1-apache
    deploy:
      replicas: 1
      placement:
        constraints: [node.labels.server == web]
    configs:
      - source: official_homepage
        target: /var/www/html/index.php
        uid: '33'
        gid: '33'
        mode: 0444
      - source: apache_vhost
        target: /etc/apache2/sites-available/000-default.conf
    networks:
      - my_network

configs:
  official_homepage:
    external: true
  apache_vhost:
    external: true

networks:
  my_network:
    driver: overlay
  1. 執行 odcker stack deploy 進行部署
docker stack deploy -c docker-compose.yml official_homepage

image
10. 檢查一下,看看 config 是不是都被容器掛載到對應的路徑

docker ps -a
docker exec -it 6476ac33e359 cat /var/www/html/index.php
docker exec -it 6476ac33e359 cat /etc/apache2/sites-available/000-default.conf

image

  • 從上圖可以看到, php:7.1-apache 被部署到 server 標籤為 web 的 node (lab2)
  • index.php 與 000-default.conf 也都被掛載到正確的路徑下了

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