2021年7月3日 星期六

Docker

Docker 實作輕量級的作業系統虛擬化解決方案,以 Linux 容器 (LXC) 等技術為基礎,進一步封裝讓使用者不需要去關心容器的管理,使得操作更為簡便。Docker 最初是 dotCloud 公司內部的一個業餘專案,採用 Google 的 Go 語言實作。專案後來加入了 Linux 基金會,以 Apache 2.0 開源。

Docker get started:

  • Build and run an image as a container
  • Share images using Docker Hub
  • Deploy Docker applications using multiple containers with a database
  • Running applications using Docker Compose

scan images for security vulnerabilities.

安裝 Docker (精確地講 Docker Engine):在 Linux 稱 Server,在 macOS/Widnows 稱 Desktop。

  • Docker Server for Linux:提供 x86_64/amd64、arm64/aarch64、和 arm (32-bit) 架構,CentOS、Debian、Fedora、Raspbian、和 Ubuntu 的 .deb/.rpm 套件。
  • Docker Desktop for Widnows。
  • Docker Desktop for macOS amd64。
  • Docker Desktop for macOS arm64
    • 支援 x86 和 ARM 架構不需要複雜的 cross-compilation 開發環境。
    • docker buildx:seamlessly integrate multi-platform builds
    • Docker Hub:identify and share repositories that provide multi-platform images.

Docker Desktop for Linux 會在虛擬電腦下執行,不同於先前的 Linux Docker Engine,images 和 containers 也不適用。

參考

  • 虛擬機器
  • container 是一個隔離的 process. That isolation leverages kernel namespaces and cgroups, features that have been in Linux for a long time. Docker has worked to make these capabilities approachable and easy to use.
  • 來自 Aqua Security 的 Liz Rice 用 Go 語言從頭建立 Container:https://youtu.be/8fi7uSYlOdc

2021年7月2日 星期五

Ubuntu Install Docker Engine

支援 x86_64/amd64、armhf、和 arm64 架構。

Docker Engine 是一個 client-server 應用,包括

  • daemon server -- dockerd 和
  • CLI client -- docker,

透過 Docker REST API 溝通。

支援 overlay2、aufs、和 btrfs storage drivers。預設使用 overlay2,如果要用 aufs 需要手動設定。

安裝方式

  • 從 Docker’s repositories 安裝
  • 下載 DEB 檔手動安裝
  • 使用 script 安裝

會建立 docker 群組,但無使用者,需要 sudo 執行 docker 指令。

執行 hello-world image 驗證安裝成功。

sudo docker run hello-world

顯示下列訊息後結束

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete 
Digest: sha256:df5f5184104426b65967e016ff2ac0bfcd44ad7899ca3bbcf8e44e4461491a9e
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

dockerd 以 root 身份執行,bind to 一個 Unix socket,需要 sudo 才能存取。加入 socker 群組的使用者可免除 sudo。Continue to Linux postinstall to allow non-privileged users to run Docker commands and for other optional configuration steps.

注意安全問題:執行 container 隱含執行 dockerd,只能開給信任的使用者。host 的目錄可共享給 container,例如 host 的 / 目錄,於是 container 可以沒有限制地更動。透過網路存取也要小心,需要加密或限制網域。

自動啟動 dockerd

設定檔:docker.service, containerd.service

參考

  1. https://docs.docker.com/engine/install/ubuntu/
  2. https://docs.docker.com/engine/install/linux-postinstall/
  • 非 root 執行 dockerd (rootless mode)
  • container 可視為應用程式一種標準包裝
  • REST API

2021年6月26日 星期六

Linux Namespaces

「containers are only isolated groups of processes running on a single host, which fulfill a set of “common” features

  • 只能 single host?
  • 跨 OS
  • 跨處理器架構?

historical beginning

chroot:改變 process 的 root directory。

  • 1979 釋出 UNIX Version 7 首次出現 chroot。
  • 現今 Linux 系統呼叫 chroot()。
  • 1991 亦稱為「jail」,因為用作 honeypot 來觀察駭客。
  • 2000 早期才有「microservices」應用。
  • 準備新的根目錄檔案架構 (複製執行檔、函式庫、設定檔等),然後 chroot。
  • 只是改變 root path,仍然可以跳出。
  • 現在 container runtimes 不再用 chroot,而改用 pivot_root(),好處是會把 old mounts 放到另外的目錄,後續可以卸載,讓檔案系統完全看不到而。
  • 有用的適當根檔案系統 (rootfs) 包含所有執行檔、函式庫、和需要的檔案架構。peeling it from an already existing Open Container Initiative (OCI) container 可透過 skopeo and umoci 輕易達成,但還是可以看到其它 process,網路也不是獨立的。

Linux Namespaces

  • 2002 Linux 2.4.19 開始出現的功能,wrap certain global system resources in an abstraction layer. 讓 namespace 內的 process 只看到自己那部份資源。
  • 2013 Linux 3.8 出現 user namespace 才有完整支援 container,有幾個 distinct namespaces 實作:mnt、pid、net、ipc、uts、user、和 cgroup。
  • 2016 九月提議 2 個額外 namespaces:time 和 syslog。(2019 三月尚未實作完成)
  • Linux namespace API 包含 3 個主要系統呼叫:
    • clone():子 process 繼承部份 execution context,如 memory space、file descriptors, 和 signal handlers。可 pass different namespace flags 給 clone() 建立 new namespaces。
    • unshare():讓 process to disassociate parts of the execution context。
    • setns():reassociates the calling thread with the provided namespace file descriptor. 結合現存的 namespace.
  • /proc/$PID/ns 提供額外 namespace 資訊,可用來 a handle for performing operations (like setns(2)) to the referenced namespace. 讓 us for example to track in which namespaces certain processes reside. One handy tool related to namespaces within this package is lsns. It lists useful information about all currently accessible namespaces or about a single given one.

mnt:不共享掛載的檔案系統

uts (UNIX Time-sharing System):不共享 domainname 和 hostname

ipc:隔離 IPC 資源,也就是 System V IPC objects 和 POSIX message queues。

pid (Process ID):讓 process 在 host 有 PID 外,在 namespace 下有另一組 PID,且可以 nested。在 namespace 內,第 1 個 process 的 PID 是 1,和一般 init process 相同特殊對待,所有 namespace 內 processe 都 re-parented 於 namespace 的 PID 1,結束 PID 1 也結束 namespace 內所有 processe。

net (Network) namespace 用來 virtualize the network stack,每個 network namespace contains its own resource properties within /proc/net. 一開始,一個 network namespace 只有 loopback 界面。每個網路界面只會在一個 namespace 出現,可以移到不同 namespace。每個 namespace 有自己的 IP 位址、routing table、socket listing、connection tracking table、firewall、和其它網路相關資源。刪除 network namespace 會刪除 virtual 界面,physical 界面會回到原本的 network namespace。

user (User ID):讓 process 在 namespace 內有另一套 user ID 和 group ID。unprivileged user ID 的 process 在 namespace 內可以是 privileged。

cgroup (Control Group) 支援 resource limiting, prioritization, accounting and controlling。

Composing Namespaces

Demo Application

2008 發明 cgroup,出現 Linux Containers (LXC) 計畫結合 cgroup 和 namespace 提供執行應用程式的獨立環境。同時,2007 Google 開始稱為 Let Me Contain That For You (LMCTFY) 的 containerization project, 設法提供一個穩定 API 驅動的設定方式,不用了解 cgroup 和內部細節。2013 Docker 基於 LXC,包裝 container 成為 image 而可以在機器間轉移,首先讓 container 成為標準軟體單元。之後一起發展 libcontainer,採用 Go 原生方式 spawn and manage containers。2015,計畫類似 Kubernetes 到 v1.0,成立 CNCF 推行 container,成立 Open Container Initiative (OCI) 致力於建立 container 格式的標準 -- OCI Runtime Specification。libcontainer 捐給 OCI,也誕生 runc 工具直接和 libcontainer 互動、解釋 OCI Runtime Specification 並執行。runc 用在許多 container ecosystem,如 containerd (used by Docker), CRI-O and podman。也有其它計畫採用 OCI Runtime Specification,如 Kata Containers 可以建立和執行包含輕量虛擬機器的 secure containers,用硬體 virtualization 技術作為第二層 defense 提供更強大的 workload 隔離。

參考

  1. https://medium.com/@saschagrunert/demystifying-containers-part-i-kernel-space-2c53d6979504 或 https://github.com/saschagrunert/demystifying-containers

2021年6月19日 星期六

busybox logger

logger [OPTIONS] [MESSAGE]

寫 MESSAGE 或標準輸入到 syslog

選項

  • -s:同時也寫到 stderr。
  • -t TAG:使用 TAG 作為標示,預設是使用者名稱。
  • -p PRIO:numeric 或 facility.level 優先權,預設是 user.notice

範例

  • logger hello

參考

  1. busybox sysklogd 原始碼

2021年6月12日 星期六

busybox syslogd

syslogd [選項]

選項

  • -n:前景執行。
  • -O FILE:日誌檔,預設 /var/log/messages。本地紀錄時,未符合規則、等級小於選項 -l、且不紀錄到 share memory 時使用。
  • -l N:只紀錄小於等級 N (1-8) 的訊息。
  • -S:較小的輸出,不放主機名稱和分類等級。
  • -m MIN:MIN 週期丟 SIGALRM 給自己,在日誌加「-- MARK --」。程式未啟用。參考 alarm()。

功能 ROTATE_LOGFILE

  • -s SIZE:rotation 大小 (KB),預設 200KB,0 不 rotation。
  • -b N:保留 N rotated logs,預設 1,最大 99,0 不保留。

功能 REMOTE_LOG

  • -R HOST[:PORT]:紀錄到遠端 IP 或主機的 PORT,預設 PORT 是 514/UDP。如果本地也要紀錄,選項要開 -L。
  • -L:紀錄到遠端時,同時也紀錄到本地。

功能 SYSLOGD_DUP

  • -D:丟棄重複的訊息。

功能 IPC_SYSLOG

  • -C[size_kb]:未符合規則且等級小於選項 -l 的,紀錄到在 share memory 的 circular buffer,使用 logread 讀取。參考 shmget()、shmat()、shmdt()、shmctl()、semget()、semop()、semctl()。

功能 SYSLOGD_CFG

  • -f FILE:指定設定檔,預設 /etc/syslog.conf。符合規則的就不會再紀錄到指定的日誌檔或 IPC share memory。

範例

  • syslogd -R masterlog:514
  • syslogd -R 192.168.1.1:601

syslogd 動作

  1. 讀取 /dev/log 訊息。
  2. 檢查有沒有重複。
  3. 紀錄到遠端話,送到遠端。沒開 -L 選項則回到 1.。
  4. 預設分類等級是 user.notice,嘗試解析訊息中 <數字>。
  5. 換行替代為空白,TAB 不變,其它 0x1F 以下的碼替代為 ^A、^B、...。
  6. 使用訊息中已有的 timestamp 或產生 timestamp。
  7. 沒設 -S 選項加上主機名稱和分類等級。
  8. 設定檔有符合的分類等級規則,本地紀錄完回到 1.。
  9. 符合紀錄等級以下,紀錄到 share memory,否則本地紀錄到選項 -O 的日誌檔。

本地紀錄的動作

  1. 如果不在同一秒,重新開啟檔案。
  2. 嘗試開啟檔案,失敗改開啟 /dev/console,再不行則用 stderr。
  3. 一般檔案進行 rotate 動作。
  4. 寫入。

參考

  1. busybox sysklogd 原始碼
  2. facilitynames[] 和 prioritynames[] 在 uClibc 的 include/sys/syslog.h

2021年6月8日 星期二

SIP P-Header

SIP 的 Private Header (P-Header) 擴充

3GPP [RFC7315] [RFC7976]

  • P-Associated-URI:在 SIP REGISTER 成功回應時告知所有相關 URI。可有多個。UA 可用這些 URI 身份,但並不表示這些 URI 已註冊。
    P-Associated-URI       = "P-Associated-URI" HCOLON
                             [p-aso-uri-spec]
                             *(COMMA p-aso-uri-spec)
    p-aso-uri-spec         = name-addr *(SEMI ai-param)
    ai-param               = generic-param
    範例 [https://community.cisco.com/t5/ip-telephony-and-phones/cisco-2811-itsp-sip-configuration-was-good-from-a-long-time-but/m-p/4163078]
    P-Associated-URI: <sip:+97440006999@vodafone.qa>
    P-Associated-URI: <tel:+97440006999>
    P-Associated-URI: <tel:+97440006900;wcard-range=+974400069![0-9][0-9]!>
    P-Associated-URI: <sip:+974400069![0-9][0-9]!@vodafone.qa>
    name-addr 的 URI 是 <> 包起來的,其中 user 或 telephone-subscriber 的 wildcard 支援
    • 有沒有標準?一般 wildcard 部份前後用 ! 包起來,放正規表示式語法,但可能不是全部支援。
    • IMS PSI 
    • Alcatel-Lucent 5060 IP Call Server (ICS) 的 wildcard PUID。PrID, pbxPUID, pbxPrID, iDN (individual Directory Number)
  • P-Called-Party-ID
  • P-Visited-Network-ID
  • P-Access-Network-Info [https://datatracker.ietf.org/doc/html/rfc7913]
  • P-Charging-Function-Addresses
  • P-Charging-Vector

Early Media 授權 [https://datatracker.ietf.org/doc/html/rfc5009]

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...