antony@notes:~/container$ cat "Setup-K3d-on-Alpine-Linux.md"
Setup K3d on Alpine Linux
Setup K3D on Alpine Linux
1. Prerequest
- 已安裝 Alpine Linux 3.20.x
2. 環境準備
以下環境設定會使用 Podman 而不是 Docker,因為 Podman 有 Docker API compatibility layer。 k3d 使用 Docker API 與 Podman v4 或更新版相容.
# 2.1. 新增套件儲存庫 (請使用 root 執行)
$ echo 'http://dl-cdn.alpinelinux.org/alpine/latest-stable/main/
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community/' > /etc/apk/repositories
# 2.2. 更新套件,並安裝 Podman
$ apk update && apk upgrade && \
apk add podman curl nano iptables-legacy sudo && exit
# 2.3. 確認 CGroup 版本為 v2
$ cat /etc/rc.conf | grep "rc_cgroup_mode"
#rc_cgroup_mode="unified"
> [註] "unified" mounts cgroups version 2 on /sys/fs/cgroup
# 2.4. Enable and start the cgroups and podman services
$ sudo rc-update add cgroups && \
sudo rc-service cgroups start && \
sudo rc-update add podman
# 2.5. Setup rootless mode with Podman
$ echo "$USER":500000:65536 | sudo tee /etc/subuid && \
echo "$USER":500000:65536 | sudo tee /etc/subgid
# 2.6. load needed kernel modules
$ echo -e "tun\nfuse\nip_tables\nip_vs\nbridge\nbr_netfilter" | sudo tee -a /etc/modules
# 2.7. 設定開機自動建置 Podman Socket 軟連結
$ sudo rc-update add local && \
echo '[[ -h /var/run/docker.sock ]] || ln -s /run/podman/podman.sock /var/run/docker.sock' | sudo tee /etc/local.d/rc.local.start && \
sudo chmod +x /etc/local.d/rc.local.start
# 2.8. 重啟主機
$ sudo reboot
# 2.9. 檢查需要的 Service 開機會自動啟動
$ sudo rc-status | grep -Ew "podman|local|cgroups"
cgroups [ started ]
podman [ started 00:03:15 (0) ]
local [ started ]
# 2.10. 檢查 Podman Socket 軟連結是否存在
$ ls -l /var/run/docker.sock
lrwxrwxrwx 1 root root 23 Jul 22 09:59 /var/run/docker.sock -> /run/podman/podman.sock
# 2.11. 下載與設定 kubectl 命令
$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
sudo chmod +x kubectl && \
sudo mv kubectl /usr/local/bin/
# 2.12. 確認 kubectl 版本
$ kubectl version --client
Client Version: v1.30.3
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
# 2.13. 安裝當前最新版本的 k3d
$ wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
# 2.14. 檢查 k3d 版本
$ k3d version
k3d version v5.7.2
k3s version v1.29.6-k3s2 (default)
# 2.15. 設定 IPVS Mode
$ sudo apk add dpkg && \
sudo update-alternatives --install /sbin/ip6tables ip6tables /sbin/iptables-legacy 10 --slave /sbin/ip6tables-restore ip6tables-restore /sbin/ip6tables-legacy-restore --slave /sbin/ip6tables-save ip6tables-save /sbin/ip6tables-legacy-save
# 2.16. 建立 Podman Network
$ sudo podman network create --subnet 172.22.1.0/24 --gateway 172.22.1.254 --subnet fd52:2a5a:747e:3acd::/64 --gateway fd52:2a5a:747e:3acd::10 c29-network3. Building a customized K3s image
# 1. 建立工作目錄區
$ mkdir -p k3d/{bin,config/{c24/addon,c29/addon},wulin}
> [註] 以上命令需要由 Bash Shell 執行才會在 k3d 目錄區底下分別建立那 3 個子目錄
# 2. 設定 K3s 的 Containerd 能夠到 dkreg 下載 Container Images
$ echo 'server = "http://dkreg.kube-system:5000"
[host."http://dkreg.kube-system:5000"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true' > ~/k3d/config/c29/hosts.toml
# 3.
$ echo '{{ template "base" . }}
# RuntimeClass Handler
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
runtime_type = "io.containerd.runsc.v1"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc.options]
BinaryName = "/usr/bin/runsc"' > ~/k3d/config/c29/config.toml.tmpl
# 3. 編輯 Containerfile
$ nano config/c29/Containerfile
# 4. Build Container Image
$ sudo podman build --no-cache -t k3s-add-runtime:v1.29.6-k3s1 ~/k3d/config/c29/3.1. Containerfile:
ARG K3S_TAG="v1.29.6-k3s1"
ARG ALPINE_TAG="3.20.2"
FROM docker.io/rancher/k3s:$K3S_TAG as k3s
FROM docker.io/library/alpine:$ALPINE_TAG
# Install OCI runtime spec (crun, runsc)
RUN apk -U add crun bash && \
ARCH=$(uname -m); URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH} && \
wget ${URL}/runsc ${URL}/runsc.sha512 ${URL}/containerd-shim-runsc-v1 ${URL}/containerd-shim-runsc-v1.sha512 && \
rm -f *.sha512 && \
chmod a+rx runsc containerd-shim-runsc-v1; mv runsc containerd-shim-runsc-v1 /usr/bin
COPY --from=k3s / /
# Configuring containerd with Base template
RUN mkdir -p /var/lib/rancher/k3s/agent/etc/containerd/cert.d/dkreg.kube-system:5000
COPY config.toml.tmpl /var/lib/rancher/k3s/agent/etc/containerd/
COPY hosts.toml /var/lib/rancher/k3s/agent/etc/containerd/cert.d/dkreg.kube-system:5000/
VOLUME /var/lib/kubelet
VOLUME /var/lib/rancher/k3s
VOLUME /var/lib/cni
VOLUME /var/log
ENV PATH="$PATH:/bin/aux"
ENTRYPOINT ["/bin/k3s"]
CMD ["agent"]4. 撰寫 k3d 叢集設定檔
# 4.1. 編輯 k3d 叢集設定檔
$ nano ~/k3d/config/c29/c29.yaml
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: c29
servers: 1
agents: 2
kubeAPI:
host: "k1.org"
hostIP: "0.0.0.0"
hostPort: "6443"
#image: docker.io/rancher/k3s:v1.29.6-k3s1
image: localhost/k3s-add-runtime:v1.29.6-k3s1
network: c29-network
token: c29Token
volumes:
- volume: /home/bigred/k3d/wulin:/opt/kadm
nodeFilters:
- "server:0"
# - volume: /home/bigred/k3d/cni:/opt/cni/bin
# nodeFilters:
# - "server:*"
# - "agent:*"
# - volume: /lib/modules:/lib/modules
# nodeFilters:
# - "server:*"
# - "agent:*"
files:
- description: 'Canal v1.27.3 Manifests'
source: addon/canal-v1.27.3.yaml
destination: /var/lib/rancher/k3s/server/manifests/canal.yaml
nodeFilters:
- "server:0"
- description: 'Runtime Class: crun, runsc'
source: addon/runtimeclass.yaml
destination: /var/lib/rancher/k3s/server/manifests/runtimeclass.yaml
nodeFilters:
- "server:0"
ports:
- port: 22100:22100
nodeFilters:
- "server:0"
- port: 5000:5000
nodeFilters:
- "server:0"
- port: 8080:8080
nodeFilters:
- "server:0"
- port: 9000:9000
nodeFilters:
- "server:0"
- port: 80:80
nodeFilters:
- "server:0"
- port: 443:443
nodeFilters:
- "server:0"
hostAliases:
- ip: 1.1.1.1
hostnames:
- cloud.flare.dns
options:
k3d:
wait: true
timeout: "60s"
disableLoadbalancer: false
disableImageVolume: false
disableRollback: true
k3s:
extraArgs:
- arg: "--cluster-cidr=10.244.0.0/16"
nodeFilters:
- server:*
- arg: "--service-cidr=10.98.0.0/16"
nodeFilters:
- server:*
# - arg: "--kube-proxy-arg=proxy-mode=ipvs"
# nodeFilters:
# - server:*
# - agent:*
- arg: "--egress-selector-mode=disabled"
nodeFilters:
- server:*
- arg: "--disable=traefik"
nodeFilters:
- server:*
- arg: "--flannel-backend=none"
nodeFilters:
- server:*
- arg: "--disable-network-policy"
nodeFilters:
- server:*
nodeLabels:
- label: app=taroko
nodeFilters:
- "server:0"
kubeconfig:
updateDefaultKubeconfig: true
switchCurrentContext: true4.1. 設定檔欄位解釋
apiVersion: k3d.io/v1alpha5,設定檔的版本,這將會在未來改變,因為我們會讓一切變得更穩定,這是必填的欄位。kind: Simple,定義要使用的設定檔案類型,在內部也有 Cluster 的設定,但尚未對外提供,這是必填的欄位。metadata,定義設定檔的重要資訊。name,要賦予 K3D 叢集的名稱 (仍將以k3d-為前綴)。
servers,定義要幾台 Control-plane 節點。agents,定義要幾台 Worker 節點。kubeAPIhost,定義 K3D 叢集的 Domain namehostIP,將監聽 Kubernetes API 的位置hostPort,Kubernetes API 在 Host 主機系統上監聽連接埠的對應位置
image,定義要使用哪一個版本 Container Image 來建立 K3snetwork,使用已經存在的 Podman Netwrok,如果沒有則會建立新的 Podman Netwroksubnet,為新建立的 Cotainer 網路定義子網路token,指定叢集的 Token,K3s 使用 Token 來保護節點加入過程,Token 會在叢集加入新節點時進行身分驗證的動作。volumes,定義在 Host 主機有哪些 Volume 要掛載進 K3D 的節點。volume,指定 Host 主機的目錄區,將之掛載到 K3D 的節點中。- 格式 :
/my/host/path:/path/in/node
- 格式 :
nodeFilters,定義要將 Volume 掛載到哪些 K3D 的節點中。- 格式 :
server:0(第一台 Control-plane),也可以用*代表每一台 Control-plane。
- 格式 :
ports,定義 K3d 叢集有哪些 Ports 要 Mapping 出來到 Host 主機。port,將 K3s 節點 (Container) 的 ports 透過 serverlb 這台 Loadbalancer Maping 到 Host 主機的 ports (via the serverlb)- 格式 :
HOSTPORT:CONTAINERPORT
- 格式 :
nodeFilters,定義要將哪一台 K3s 的節點中的 Port Mapping 到 Host 主機上。- 格式 :
loadbalancer
- 格式 :
env,將環境變數加入節點。envVar,宣告要定義的環境變數。- Example:
bar=baz
- Example:
nodeFilters,定義要將環境變數加入哪台 K3d 節點。- Example:
server:0
- Example:
files,定義要自動部屬哪些 Workload 在 K3d 叢集中。description,描述 Workload 的字串source,Workload 的 Yaml 檔內容,格式可以直接是檔案內容,或給檔案名稱。- Example1 :
source: | apiVersion: v1 kind: Namespace metadata: name: foo - Example2 :
source: ns-baz.yaml
- Example1 :
destination,Workload 的 Yaml 檔儲存在 K3d 節點中的哪個目錄區。- 格式: 可以是絕對路徑或相對路徑。
- Example1 :Workload 的 Yaml 檔實際會被存儲存成
destination: k3s-manifests-custom/foo.yaml/var/lib/rancher/k3s/server/manifests/custom/foo.yaml - Example2 :用絕對路徑定義 Workload 的 Yaml 檔,並指定要儲存在哪些 K3d 的節點上。
destination: /var/lib/rancher/k3s/server/manifests/baz.yaml nodeFilters: - "server:*"
- Example1 :
- 格式: 可以是絕對路徑或相對路徑。
hostAliases,定義要寫入到 K3D 叢集結點中的/etc/hosts檔案內容和 CoreDNS 的 NodeHosts 部分中ip,服務的 IP Addresshostnames,服務的名稱
optionsk3d,k3d runtime 的設定wait: true,等待群集可用後才返回timeout: "60s",定義建置 K3D 叢集超時的時間,如果超過時間會停止建立的動作。disableLoadbalancer: false,停用在 Contol-plane 節點前面建立 LoadBalancer。disableImageVolume: false,不要為 K3D 節點的根檔案系統建立永存的 VolumedisableRollback: false,如果叢集建立失敗,不要回溯變更。loadbalancer,設定 Nginx Loadbalancer 的設定檔configOverrides,要覆蓋的設定值- Example:
settings.workerConnections=2048
- Example:
k3s,設定 K3s 本身extraArgs,傳給k3s server|agent指令的附加參數;與--k3s-arg相同- Example:
k3s: extraArgs: - arg: "--tls-san=my.host.domain" nodeFilters: - server:*
- Example:
nodeLabels,定義要對哪一台 K3s 的節點貼上標籤- Example:
nodeLabels: - label: foo=bar nodeFilters: - agent:1
- Example:
kubeconfig,設定 KubeConfigupdateDefaultKubeconfig: true,會把建立好的 K3s 叢集加到預設的 KubeConfig 檔案中。switchCurrentContext: true,會將 KubeConfig 檔中的 Current Context 切換到新建立好的叢集。
runtime,設定 Container Runtime (Podman/Docker)gpuRequest: all,要新增至 K3s 叢集節點的 GPU 裝置。all會把所有 GPU 裝置都掛載進去。
labels,要對 Host 主機上的 K3s 節點 (Conttainer) 貼哪些標籤。- Example:
labels: - label: bar=baz nodeFilters: - agent:1
- Example:
ulimits,設定 Process 的資源name: nofile,限制 Open File 的數量 (max number of open file descriptors)soft: 26677,在任何指定時間內,允許一個程序使用的最大的 Open File 數量。hard: 26677,即使暫時超過 soft limit,程序仍可使用的最大的 Open File 數量。
例如,預設情況下,一個程序可以擁有的開啟檔案數量的 soft limit 是 1024。這表示一個程序在任何時候最多可以有 1024 個開啟的檔案。但是,如果程序嘗試開啟超過 1024 個檔案,則不允許這樣做。預設開啟檔案數量的 hard limit 為 4096。這表示,即使暫時超過 1024 的 soft limit,程序開啟的檔案也不會超過 4096 個。 soft limit 之所以有用,是因為它們允許程序暫時超過其限制而不會造成問題。例如,Web 伺服器在處理大量流量時,可能需要開啟大量檔案。soft limit 允許網頁伺服器在不當機的情況下執行此動作。但是,hard limit 可以防止 Web 伺服器使用過多資源而導致系統出現問題。 soft limit 和 hard limit 可以為每個使用者和每個程序設定。預設限制由系統管理員設定,但使用者可以變更自己的限制。要變更 soft limit 或hard limit,可以使用
ulimit指令。
5. 準備 Auto-Deploying Manifests
$ wget --no-check-certificate --no-cache -P ~/k3d/config/c29/addon/ https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/canal.yaml6. 在 K3s 中甚麼是 Tunnel Proxy? 為什麼要使用它? K8s 為什麼沒有?
在 K3s 中預設都會有 Tunnel Proxy,它的功能是讓 API Server 和 Worker Node 節點之間做溝通。
因為 K3s 在設計的時候是給