ref: https://medium.com/swlh/quick-fix-sharing-persistent-disks-on-multiple-nodes-in-kubernetes-ef5541fd8376
這篇文章是 kubernetes 與 Storage 整合的經驗分享文,該文章包括了下列內容
Cloud Storage, NFS, Kubernetes, PV/PVC.
Kubernetes 內針對這些儲存相關的使用方式有
1. 使用 ephemeral 的儲存設備
ephemeral 只適合暫存資料使用,因為該儲存設備不是持久保存的,這意味 Container 如果重啟,資料就會消失。
2. 使用 Bind Mount 的方式將資料從節點掛載到容器中
就如同過往使用 Docker 時會使用 -v 的方式將同節點中的儲存目錄給掛載到容器中來使用。
基本上有任何永久性儲存的需求都會採用(2) 這個方式來處理,而目前很多 Cloud Provider 都有提供相關的儲存裝置讓你的 VM(k8s Node)
可以輕鬆存取與使用。
舉例來說,AWS 有 EBS, GCP 有 GPD,這類型的 Block Storage Device 本身支援動態掛載與卸載,所以就算 Kubernetes 將目標 Container 重新部署到
不同節點上也不需要擔心資料會不同,因為這些 Storage 可以隨者不同節點動態掛載上去,讓你的 Container 看到相同的資料。
但是以上兩個裝置都有一個限制,就是並不支援同時多人寫入的動作,於 Kubernetes 只能使用 Read/Write 模式。
這意味每個 Storage 同時只能有一個 Container 去進行讀寫操作(but Azure 的服務就沒有這個限制)
作者假設今天有一個服務底層是由三個元件組成,這些元件會需要針對相同一個資料集一起處理。
舉例來說有服務 A,B,C
A: 將資料寫入到儲存系統中
B: 從儲存系統中讀入資料進行二次處理,處理完畢再寫回去儲存系統中
C: 將資料從儲存系統中讀出並且供外部使用
上述情境簡單說就是一個儲存設備,會有三個服務同時想要讀取,一個專心寫,一個同時讀寫,一個專心讀。
這種需求就沒有辦法單純使用 EBS/GPD等裝置來使用,因此作者接下來就會針對如何使用 NFS 這套網路儲存系統來搭建一個符合上述需求的用法。
該解決方案流程如下
1) 透過 EBS/GPD 的方式掛載一個儲存空間到 k8s 節點中
2) 部署一個 NFS Server 的容器到 Kubernetes 中,該 NFS Server 會使用 EBS/GPD 作為其儲存空間的來源
3) NFS Server 透過 service 分享服務
4) 部署 PV/PVC 物件到 Kubernetes 中
5) A,B,C 三種容器透過 PVC 的方式來存取 NFS Server
因為 NFS 本身就是一個可多重讀寫的解決方案,作者透過這種方式讓多個應用程式可以同時讀寫,同時將這些資料保存到 EBS/GPD 的儲存空間中。
不過這種用法帶來的問題可能就是速度問題,從同節點直接存取變成透過網路存取,所以如果本身對於存取有非常高的頻寬需求時,使用這種解決方案也許會遇到
很難解決的瓶頸,畢竟大部分人的 k8s 叢集都是 data/control 兩種資料交雜於底層的網路架構中,沒有辦法將 data plane/control plane 給分開來。
有興趣看作者如何一步一步搞定上述流程的可以參考全文
「docker --mount」的推薦目錄:
- 關於docker --mount 在 矽谷牛的耕田筆記 Facebook 的最讚貼文
- 關於docker --mount 在 矽谷牛的耕田筆記 Facebook 的最讚貼文
- 關於docker --mount 在 矽谷牛的耕田筆記 Facebook 的精選貼文
- 關於docker --mount 在 How to Save Docker Data using Bind Mounts or Volumes 的評價
- 關於docker --mount 在 Create and bind mount file in Docker - Stack Overflow 的評價
- 關於docker --mount 在 Bind Mounts – Features in Docker – Complete Intro to ... 的評價
- 關於docker --mount 在 Docker volume mount using CLI command 的評價
docker --mount 在 矽谷牛的耕田筆記 Facebook 的最讚貼文
ref: https://sysdig.com/blog/dockerfile-best-practices/
如果你常用到容器化、微服務架構,這些輕量化的架構當碰到問題時,背後的資安事件調查、報告、修復卻是影響甚鉅。然而,這些影響都可以透過「把安全意識擺在開發階段 (shifting left security)」來降低風險,而這篇文章就會講述 Dockerfile 的最佳實作手段有哪一些。
首先,我們會從幾個大面向來說明各種控制安全風險的細節,像是權限控管、降低攻擊層面、預防機敏資料洩漏,以及在發布 container image 時的注意事項。而你需要特別注意的是,其實 Dockerfile 也只是算是開發階段的一部份,所以這邊能提醒到的內容都屬於部署前(特別是開發階段)的準備。以下共提及 20 個你可以注意的重點,但因為篇幅較長,筆者將選出較重要的幾個來談談。
讓我們從「權限控管」說起:
Rootless container
根據報告結果顯示,有超過 58% 的 image 都是用 root 作為執行服務的使用者,所以在此也會建議透過 USER 參數來設定容器的預設使用者,同時,也可以利用執行環境/架構的設定來避免容器的預設使用者是 root。
Make executables owned by root and not writable
服務的 binary file 應該避免被任何人修改,容器的預設使用者只需要執行服務的權限,而不是擁有權。
至於「減少攻擊面」的部分:
Multistage builds小
在 image 的建立,可以透過 multistage build 來建立很多層 container,例如在第一層安裝編譯所需的套件,而第二層則只需安裝 runtime 所需的套件(如 openssl 等),再複製第一層所編譯出來的執行檔就可以了。其餘的因開發/編譯所安裝的套件皆不需要放在最後的 image,這樣同時也可以把 image 的大小縮小。
Distroless & Truested image
採用最小/最輕量化的 base image 來作為你打造 image 的基礎,同時使用可信任來源的 image,避免不小心在未知的情況引入好幾個潛在的安全威脅。(在原文中,sysdig 也使用了自身開發的工具來檢測 image 是否有安全問題,如果有需要也能參考看看)
而再來關於「機敏資訊」的部分:
Copy
當你在從你的開發環境複製檔案到 image 當中時,需要非常小心,因為你很可能一不小心就把你的密碼、開發環境的 token、API key 等資訊複製進去了。而且不要以為把 container 裡面的檔案刪掉就沒事了,別忘了 container image 是一層一層堆疊起來的,就算刪掉了,還是能在前面的 layer 裡面找到。
但如果還是有需要用到這些機敏資料,也可以考慮使用環境變數(docker run -e 引入),或是 Docker secret、Kubernetes secret 也能夠幫你引入這些參數。如果是設定檔的話,則可以用 mount 的方式來掛載到你的 container 裡面。
總而言之,你的 image 裡面不該有任何機敏資料、設定檔,開發服務時讓服務在 runtime 的時候可以接受來自環境變數的參數才是相對安全的。
其他的部分:
其實文章當中還有提到很多製作 image 的注意事項,像是在 deployment 階段,可能你部署的 latest 與實際的 latest 因時間差而不同。又或是在 image 裡面加上 health check,也才能做到狀況監測。
在容器化服務的時代,開發者不僅需要具備撰寫開發程式的能力,也要對於虛擬化環境有足夠的理解,否則,在對架構不熟的情況就將服務部署上去,或把 image 推送到公開的 registry,都可能造成重要的資料外洩與潛在的資安危機。
docker --mount 在 矽谷牛的耕田筆記 Facebook 的精選貼文
本文是一篇 2017 年的文章,雖然已經四年之久,但是我認為本篇文章值得一讀。
作者團隊於 2017 年時正在經歷如何將 VM 上的各種 Java 應用程式轉移到 Kubernetes 內的 Container,而本篇文章則是探討到底 Container 是如何透過 Linux Control Group 以及 namespace 實作的,透過對這些底層實作的瞭解,才有辦法針對 Container 效能部分去除錯與提升。
這種文章探討的都是很底層的概念,建議所有人都閱讀一遍,好好複習關於 cgroups/namespace 的概念,透過對這些概念的理解與掌握,能夠更有系統的去解釋何謂Docker Container,何謂輕量級虛擬化。
以下幫大家節錄一些重點,還是推薦自行閱讀全文
1. cgroup 用來隔離與限制 CPU,Memory,Disk,Network Bandwidth 等資源的用量
2. namespace 則是用來限制 ipc, pid, mount ,network, utc 等資訊的可視性,不同 namespace 內看到的資訊是獨立的,但是最終彼此還是屬於同一個 Kernel。
3. 任何沒有被 cgroup 規範的應用程式都會被自動包含到 root cgroup 的規範,不同發行版其位置不同,譬如 /sys/fs/cgropu.
假設今天透過 docker run 去運行一個 java 應用程式
a. Docker 會創建一個 pid namespace,接者運行 Java 前先把該應用程式給掛到新的 pid namespace 上並且賦予該 java 應用程式 PID 1
註: Host 上還是可以觀察到該 Java 應用程式,因為除了 Host 本身外,每個 pid namespace 都有自己的老爸,而老爸是可以看到小孩資訊的,這意味 docker dameon 雖然創建新的 pid namespace,但是host的pid namespace 實際是新 namespace 的老爸
b. 從老爸的視角來看,可以看到該 Java 應用程式也會有一個不同的 PID,而這個 PID 也會於 cgroup 系統中有自己的設定
4. CPU Cgroup 則是會用 share 為單位來定義每個 task 可以獲得多少相對的 CPU 時間,相對的算法是去計算 task 擁有的 share 數量佔了整個 cgroup 階層元件中的多少百分比。
舉例: 捨去其他服務單純考慮運行三個 Container 且有 4 Core CPU 的環境,三個 Container Task 分別給予 2048,1024,1024 share 的話,第一個 Container 大致是會被分配到兩個 CPU Time
5. CPU shares 沒有辦法去保證每個 task 最小用量是多少,所以需要透過 CPU Quotas 的概念來設定 CPU.cfs_quota_us(假設使用 CFS 這個排成演算法)以及 CPU.cfs_period_us(預設100ms)。
概念大概就是 cfs_period_us 定義的時間內,你最小可以使用多少時間,所以假如設定 cfs_quota_us 為 100ms,則預設情況下該 process 可以使用的量就是 100ms/100ms = 1 ~= 1 Core CPU
k8s 與上述的相關bug 可參考下列 issue
https://github.com/kubernetes/kubernetes/issues/67577
6. JVM 看到的是系統上全部的 CPU 資源,但是 Contaienr 本身當被限制 CPU 用量時,會有資訊落差,造成 GC 運行的效果不如預期,因為其認為系統有超多 CPU,而不知道自己其實被限制的CPU很少。
原文滿精彩的,推薦閱讀
https://engineering.squarespace.com/blog/2017/understanding-linux-container-scheduling
docker --mount 在 Bind Mounts – Features in Docker – Complete Intro to ... 的推薦與評價
Bind mounts allow you to mount files from your host computer into your container. This allows you to use the containers a much more flexible way than previously ... ... <看更多>
docker --mount 在 How to Save Docker Data using Bind Mounts or Volumes 的推薦與評價
Using Docker for a database is common during development. It's easy to set up, and it's available for many different types of databases. ... <看更多>