Skip to main content

3 posts tagged with "k8s"

View All Tags

· 2 min read
zaxro

app-development-and-delivery-with-cloud-code-gcb-cd-and-gke.svg

Cloud Build在這個lab會做到

  • Use Build trigger to monitor changes to the source repo.
  • When a change is committed into main branch, Cloud build trigger following:
    • Build artifacts in cloud storage bucket
    • Run test on the container
    • Place the app image in Artifact Registry
    • Call Cloud deploy to deploy the container to the staging environment.
  • If all the build and tests are succesful, you can use Cloud Deploy to promote the container from staging to production.

Cloud deploy會註冊並管理pipline跟targets(指的是staging and production cluster).

這邊整理這個lab的建構過程,詳細步驟可以依照官網資源做學習.

官網大致流程:

  1. 設定預設專案.會用到的指令gcloud config set project PROJECT_ID,可以用gcloud config get-value project檢查目前預設專案,查詢有哪些專案可以用gcloud projects list

後續的lab會拿我自己寫的程式,它原本是部署在docker上,會把它改成gke版本,config的放入會試試看config map跟 headless service等東西!

使用cloud deploy執行環境

  1. cloud build worker pool 會讓deploy在該池中執行部署及驗證
  2. cloud deploy需調用執行操作的帳號
  3. cloud storage 的清單存放位置

· 10 min read
zaxro

why k8s? It allows for easy scalability, high resilience, application portability, automation of many tasks, and standardization of the container platform

先看到以下這張圖,這是官方提供的k8s組成,你會注意到幾個關鍵元件:Kubernetes cluster,Control plan, Node.簡言之,kubernetes cluster由多個worker node(硬體資源)及control plane組成.

k8s-strucuture

Kubernetes基本運作: worker node會託管pod(以容器化建立的應用程式),而control plane會管理cluster內的worker node跟pod.

細部看,這幾個關鍵元件底下也是由多個元件組成.以下簡單介紹control plane,pod,woker node的組成.

control plane

控制平面對集群做出全局決策,並檢測及回應集群事件,例如:檢測到部署的pod不滿足deployment應部署的pod數量時,會起新pod.由kube-apiserver,etcd,kube-scheduler ,kube-controller-manager,cloud-controller-manager組成!

kube-apiserver

kube-apiserver是API伺服器,為 Kubernetes 控制平面的前端,主要負責公開k8s的api.從 Command Line 下 kubectl 指令就會把指令送到這裏,同時也是不同node之間溝通的轉介點.

etcd

etcd是key value存儲庫,用來放k8s的集群數據,這邊資料建議要有備份計畫

kube-scheduler

kube-scheduler它監視新創建的未分配節點的 Pod,並為它們選擇一個節點來運行,這個選擇過程可以與資源需求、硬件/軟件/策略約束、親和性和反親和性規範、數據本地性、工作負載之間的干擾以及截止期限等有關!

kube-controller-manager

kube-controller-manager運行控制器進程,每個控制器是獨立process,這些 Process 會在 Cluster 與預期狀態(desire state)不符時嘗試更新現有狀態(current state).控制器有許多不同類型:

  1. Node 控制器:負責在節點關閉時通知並響應。
  2. Job 控制器:監視代表一次性任務的 Job 對象,然後創建 Pods 來執行這些任務直到完成。
  3. EndpointSlice 控制器:填充 EndpointSlice 對象(用於提供服務和 Pods 之間的鏈接)。
  4. ServiceAccount 控制器:為新的命名空間創建默認的 ServiceAccount。 除以上還有很多其他類型的控制器!

cloud-controller-manager

cloud-controller-manager內置了特定於雲端的控制邏,如果有用到雲端服務才會用到它,cloud-controller-manager 允許將集群與雲提供商的 API 連接起來,並將與該雲平台交互的組件從僅與您的集群交互的組件中分離出來。

pod

一個 Pod 對應到一個應用服務,一班情況最好一個pod一個container,而每個 Pod 都有一個身分證,也就是屬於這個 Pod 的 yaml 檔.同pod的container彼此可以透過port溝通.

worker node

每個 Node 中有這幾個組件kubelet、kube-proxy、Container runtime

kubelet

每個工作節點上運行的 kubelet 首先會註冊到control plane,接著它負責與control plane溝通,管理pod狀態並確保容器在 Pod 內運行.主要透過各種機制提供一組PodSpecs並確保PodSpecs 中描述的容器運行並保持健康。

kube-proxy

kube-proxy 在 Kubernetes 集群中做網路管理,負責維護節點間的通訊和更新 iptables 規則,以確保服務和 Pod 的正確運行和通信。同時,它也促使節點間的資訊同步,使得 Kubernetes 中的各個組件可以準確地獲取節點上所有 Pods 的狀態。

Container Runtime

容器運行時是負責運行容器的軟體。

部署服務過程

k8s如何部署服務?

簡單過程: 透過指令建立deployment,control plane會依據deployment設定出需求的pod.

較詳細過程於以下:

  1. 使用 kubectl 命令建立deployment資源,過程會將 YAML 資源文件轉換為 JSON 格式,然後將其發送到位於控制平面內的 API Server。

  2. API Server 收到請求後,將部署的詳細信息或對象定義持久化到etcd數據庫中。

  3. 當 etcd 存儲中添加了新的 Deployment 資源後,API Server 會將相關的事件通知controller manager,controller manager創建足夠的 Pod 資源以匹配 Deployment 中的副本數量。此時,在 etcd 中的部署狀態為「Pending」。

  4. Scheduler檢測到「Pending」狀態後,會檢查基礎設施的狀態,對節點進行篩選和排序,以決定在哪個節點上建立 Pod。然後,Scheduler根據其業務邏輯填充 Pod 的 Spec 中的「nodeName」字段,並將已調度的 Pod 對象以「Scheduled」狀態持久化到 etcd 中.

  5. 一旦Pod被調度到Wokernode上,kubelet 會負責創建Pod中定義的容器。

  6. Pod 調度: 當 kubelet 從 API Server 獲取到新 Pod 的規範後,它會檢查該規範,然後使用container runtime(如 Docker)創建相應的container。kubelet 會監控容器的運行狀態,並在需要時重新啟動容器。

  7. 健康檢查: kubelet 會執行就緒探針(readiness probe)和存活探針(liveness probe),以確定容器是否就緒並保持運行狀態。如果探針指示容器不健康,kubelet 可能會重新啟動該容器。

  8. 報告狀態: kubelet 會定期向 API Server 報告它所管理的 Pod 的狀態。這包括該 Pod 是否正常運行、就緒狀態等信息。API Server 使用這些狀態信息來更新control plane的資源狀態,無問題Pod 的狀態變為「Running」,Deployment 的狀態變為「Ready」.

pod間的溝通

比較大型的程式會有很多個pod,他們之間要如何傳遞資訊? 在VM用的是固定的ip跟port,而在k8s因為會牽涉到自動擴展,用ip跟port去溝通顯然會遇到找不到ip跟port的問題. 所以k8s發展了抽象層service來抽象化這個過程,並透過kube-proxy做實際的流量轉發.

service類型

服務可以使用不同的類型,如 ClusterIP、NodePort、LoadBalancer 和 ExternalName。這些服務類型提供了不同的方式來實現 Pod 間和集群內外的通訊。

  • ClusterIP: 默認的服務類型,將 Pod 部署到集群內部,並使用集群內部的 IP 地址進行通訊。這對於集群內部的 Pod 之間的通訊非常有用。

  • NodePort: 將一個服務公開到集群節點的某個端口上,並使用該節點的 IP 和該端口進行訪問。Kubernetes 會在每個節點上打開一個高隨機端口(通常在範圍 30000-32767),並將這個端口映射到你指定的服務的目標端口, 當有多個服務使用 NodePort 且指定相同的高隨機端口時。這可能會導致一些服務衝突,或者不正確地路由到其他服務上。

  • LoadBalancer: 在支援的雲提供商上,可以創建外部負載均衡器,並將其配置到服務上。這使得外部流量可以通過負載均衡器轉發到服務內的 Pod。

  • Ingress: Ingress 是一個控制器,用於管理外部對集群中服務的訪問。通過 Ingress,你可以設定不同的路由和規則,並將流量導向到不同的 Service 或 Pod。Ingress 支援 SSL/TLS 加密、主機名和路徑的路由,是一個更高級的方式來管理外部訪問。

  • ExternalName: 通過 CNAME 記錄將服務名稱映射到外部的 DNS 名稱。這對於需要將內部服務與外部服務關聯起來的場景很有用。

小結

Kubernetes 部署程式需要透過 Deployment 創建 Pod 並管理與更新,而各個 Pod 之間的溝通通常透過 Service 提供穩定的 DNS 名稱和 IP 地址,讓 Pod 間可以使用標籤進行通訊,從而實現彈性、可靠的通訊機制。

· 6 min read
zaxro

安裝 kubeadm 遇到的問題

kubeadm 用於建立和管理叢集的基礎結構,而 kubectl 用於操作和管理叢集中的資源。這兩個工具在 Kubernetes 的部署和管理中扮演著不同的角色,安裝的官網介紹,

  1. 先安裝 docker(這邊是參考官網,也可以用其他種 container)
info

因為原本 centos 是內建 podman,但這邊為了符合 k8s 網站的教學所以使用 docker,我自己在安裝 docker 過程會遇到跟 podman 的衝突,像這樣

Docker CE Stable - x86_64                                                                                                                    133 kB/s | 3.5 kB     00:00
错误:
问题 1: problem with installed package podman-docker-3:4.3.1-2.module_el8.8.0+1254+78119b6e.noarch
- package docker-ce-3:24.0.2-1.el8.x86_64 conflicts with docker provided by podman-docker-3:4.3.1-2.module_el8.8.0+1254+78119b6e.noarch
- package docker-ce-3:24.0.2-1.el8.x86_64 conflicts with docker provided by podman-docker-3.1.0-0.13.module_el8.5.0+733+9bb5dffa.noarch
- package docker-ce-3:24.0.2-1.el8.x86_64 conflicts with docker provided by podman-docker-3.3.0-0.15.module_el8.5.0+870+f792de72.noarch
- package docker-ce-3:24.0.2-1.el8.x86_64 conflicts with docker provided by podman-docker-3.3.0-0.17.module_el8.5.0+874+6db8bee3.noarch
- package docker-ce-3:24.0.2-1.el8.x86_64 conflicts with docker provided by podman-docker-3.3.0-2.module_el8.5.0+877+1c30e0c9.noarch

解法是先移除 podman,並優先使用 docker 的 repo.安裝在 centos 可以看這篇

  1. 移除 podman
yum remove podman
  1. 擴展工具集
yum install -y yum-utils
  1. 添加軟體庫
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  1. 修改權限,把/etc/yum.repos.d/docker-ce.repo加上 priority=10,這樣就不會跟/etc/yum.repos.d/CentOS-Stream-AppStream.repo衝突!
/etc/yum.repos.d/docker-ce.repo
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://download.docker.com/linux/centos/8/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
priority=10

5.安裝 docker

yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

6.起服務

systemctl start docker
  1. 安裝 kubelet kubeadm kubectl
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

sudo systemctl enable --now kubelet

基本上這邊會發現 kubelet 服務報錯無法起來,接著是講解法!

  1. 使用kubeadm init依然會報錯,這個指令目的是建立 master node(也就是 control plane),包括 API Server、Controller Manager 和 Scheduler。當您運行 kubeadm init 時,它將生成初始化控制平面所需的配置文件、證書和其他資源。kubeadm init報錯如下
    [ERROR CRI]: container runtime is not running: output: time="2023-05-29T16:13:25+08:00" level=fatal msg="validate service connection: CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"

以上報錯如何解決

這個問題是因為/etc/containerd/config.toml設定有問題的關係 ,解法有兩種

  • 最簡單解法把/etc/containerd/config.toml 刪掉(可以先備份),這會讓 k8s 使用預設資料
rm /etc/containerd/config.toml
  • 比較複雜解法就要了解 /etc/containerd/config.toml 如何設定,預設是 disabled_plugins
disabled_plugins = ["cri"]

要改成 enabled_plugins,表示啟用 CRI 插件,因為 k8s 預設使用 CRI(Container Runtime Interface)來管理跟運行容器,如果禁用 CRI 插件或没有指定有效的容器配置,Kubernetes 將會報錯!

enabled_plugins = ["cri"]
[plugins."io.containerd.grpc.v1.cri".containerd]
endpoint = "unix:///var/run/containerd/containerd.sock"
  1. allow user to use this cluster
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
  1. Setup Your Pod Network
  • 建立檔案network.yml
network.yml在這!
network.yml
---
kind: Namespace
apiVersion: v1
metadata:
name: kube-flannel
labels:
k8s-app: flannel
pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: flannel
name: flannel
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
- apiGroups:
- networking.k8s.io
resources:
- clustercidrs
verbs:
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: flannel
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: flannel
name: flannel
namespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-flannel
labels:
tier: node
k8s-app: flannel
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-flannel
labels:
tier: node
app: flannel
k8s-app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni-plugin
image: docker.io/flannel/flannel-cni-plugin:v1.1.2
#image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.2
command:
- cp
args:
- -f
- /flannel
- /opt/cni/bin/flannel
volumeMounts:
- name: cni-plugin
mountPath: /opt/cni/bin
- name: install-cni
image: docker.io/flannel/flannel:v0.22.0
#image: docker.io/rancher/mirrored-flannelcni-flannel:v0.22.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: docker.io/flannel/flannel:v0.22.0
#image: docker.io/rancher/mirrored-flannelcni-flannel:v0.22.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: EVENT_QUEUE_DEPTH
value: "5000"
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
- name: xtables-lock
mountPath: /run/xtables.lock
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni-plugin
hostPath:
path: /opt/cni/bin
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
  • 套用設定檔
kubectl apply -f network.yml

會出現以下代表成功

namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

檢查確認是否 control plane 是 ready.

kubectl get nodes #確認是否為ready

NAME STATUS ROLES AGE VERSION
73gogo Ready control-plane 3h9m v1.27.2