Docker[3]K8s
Kubernetes因為是很長的單字加上有點難唸?所以大家簡稱為K8s。
K8s介紹
歷史
一套自動化容器運行維護的開放原始碼平台,運行維護包含 部署、排程、節點叢集間的擴充。K8s是容器技術發展下的產物,例如現在多數公司用來管理Docker容器。K8s是由Google所提供的系統並開放原始碼,藉由其管理數以億計的容器經驗所撰寫的系統。也因為雲端技術的發展,多數軟體需要藉由網路與他人共享,因此因為容器解決了環境設定問題,而被更多人所採用,一個企業平均需要用到的容器數日益增加,因此K8s被多數企業給採用。
為什麼使用?
- 快速精準地部署、即時伸縮應用程式
- 限制硬體所需資源
- 可移動、擴充、自動部署修復複製等
- 滿足一系列產品內程式的執行需求
重要元素
Pod
k8s中的最小單位,可包含一個或多個container(通常是一個,稱為pause container)。是container的抽象化,用k8s對Pod進行操作,而非直接對container動作。
每一個Pod有自己的虛擬IP位置,Pod互相可用這樣內部的IP聯絡(endpoint的概念),但缺點是Pod掛掉時IP會一起消失,重建也會指派新的,造成應用程式內部溝通失敗。
Service用來改善IP問題,是永久的IP位置,且在Pod掛上的service和Pod本身的life cycle不相關。
當使用Deployment複製多個pods時,Service同時也是load balancer
Ingress處理對外網路連到內部各網之間的關係。
app要與DB相連的資訊通常都是建立在app之中,這時候若需要改動一些DB相關東西時,還需要到app內部更改設定,不僅麻煩也容易出錯,因此ConfigMap就可用來處理這類的configuration,也就是把設定搬到app和DB之外,利用K8s中各pods的endpoint(service)相連。
注意不可以將機密資料放在這裡!!!
Secrets功能就如同ConfigMap,但是可用來存放機密資料。
Volumes
如果用來存Data的pod被重啟,那麼這些資料就會不見,因此會用到Volumes來存取,volumes會和物理層面的儲存相連,例如本地的硬碟空間、遠端儲存(和K8s本身無關)。
注意K8s本身不管資料儲存的一致性,需要自己將這一塊儲存設定好
Deployment & StatefulSet
單一個app若壞掉的話,會造成服務中斷,是不可以的!因此會有複製一個或多個app的想法,K8s當中可以用Deployment來辦到,增加/縮小 規模,而這樣複製pods的行為不可以用在DB上,因為會造成各DB資料的不一致,K8s以StatefulSet處理,但不容易使用,因此多半會把DB放在K8s cluster之外。
Node節點 &Master主控
Nodes組成Cluster叢集,Cluster是用來計算、儲存和網路資源的集合,執行各種應用程式的基礎。Nodes分為master node和worker node。
Worker Node裡面有很多Pods,每個Node都會設置有3個processes:
Container runtime
Pod 是由 container組成,container runtime就是container engine中的低階元素,例如Docker、CRI-O。
Kubelet
讓container和node之間可以互動;讓pod得以用內部的container啟動。
Kube Proxy
cluster通常以多個nodes串成,pods彼此之間透過service聯繫。Kube Proxy幫助將接收到的請求轉接到適合的pod上,例如:當一要求存取node1的app時,會優先導向相同node中的DB。
Master node用來操作worker nodes,當中有4個processes:
API Server:當client向其發送請求,會先碰到它,可做到 Auth的驗證 。
Scheduler:查看現有worker node的使用情況,並決定要將新的pod放在哪一個node。
只決定要放哪一node,真正啟動pod中container仍是kublete執行的
Controller manager:偵測cluster的狀態,當有部分pods潰堤時,會通知scheduler指派新的pods。
etcd:Key Value Store,是cluster的大腦!任何cluster中的改動都會存在這裡。
建立新的Master/Node server:
- 取得一新(沒有內容的)server
- 安裝所有master/worker node所需的processes
- 將其加入指定cluster
Minikube & Kubectl
Minikube
一般來說Cluster需要有多個master nodes 和 worker nodes組成, 也就是需要有多個個別的虛擬/實體 服務器來執行。但若我們只想測試或練習使用相關功能,可以用minikube,建立一個虛擬機作為cluster的概念,執行模式是將需要用到的master/worder processes建立在一個node之上 (作為cluster)。裡面已經內建Docker。
Kubectl
要操作Minikube建立元素時,會使用kubectl來操作像是:建立pods、services、消除pods等,可用UI、API、CLI等三種clients端操作。不只能用來操作Minikube,也支援許多類似的apps。
Download
- minikube
- kubectl
- hyperkit (或其他虛擬機)
以上都可以用homebrew安裝,且minikube會自動安裝相依套件kubectl
Start minikube
Start minikube using hyperkit as virtual environment
$minikube start --vm-driver=hyperkit
Get status of nodes
$kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 4m46s v1.24.1
$minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
Kubectl Version
$kubectl version
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.2", GitCommit:"f66044f4361b9f1f96f0053dd46cb7dce5e990a8", GitTreeState:"clean", BuildDate:"2022-06-15T14:14:10Z", GoVersion:"go1.18.3", Compiler:"gc", Platform:"darwin/amd64"}
Kustomize Version: v4.5.4
Server Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.1", GitCommit:"3ddd0f45aa91e2f30c70734b175631bec5b5825a", GitTreeState:"clean", BuildDate:"2022-05-24T12:18:48Z", GoVersion:"go1.18.2", Compiler:"gc", Platform:"linux/amd64"}
Basic kubectl commands
Check
s可加可不加。輸出更多可在後面加-o wide
。
$kubectl get nodes
$kubectl get pods
$kubectl get services
$kubectl get deployments
$kubectl get replicaset
Create
欲建立一pod,但可以發現在create 參數中並沒有pod這選項,因為在K8s中我們是用Deployment來操作pod!
$kubectl create deployment NAME --image=image
$kubectl create deployment nginx-depl --image=nginx
當創建deployment時,會自動有建立pods的blueprint,裡面有基本的configuration(name, image to use)。
Edit
$kubectl edit deployment NAME
會顯示自動產生的configuration file (with default value)。如果這時做些修改,可以看到舊的pod狀態顯示已經結束,同時也有一個新的pod正在運作中。
[yehs1225@YehTzuHsuansMBP] ~
❯ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-depl-58458fcbd-9c765 1/1 Running 0 12m
nginx-depl-68b5c6ddf6-8kcr7 0/1 ContainerCreating 0 28s
[yehs1225@YehTzuHsuansMBP] ~
❯ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-depl-68b5c6ddf6-8kcr7 1/1 Running 0 64s
Debug
$kubectl logs [POD NAME]
$kubectl describe pod [Pod NAME]
$kubectl exec -it [Pod NAME] --bin/bash
Use configuration file (.YAML)
當要創立deployment時,如果有較多參數要打(例如image有很多),直接打成一行很不方便,因此可以設定configuration file (為.yaml檔)。以下面指令來使用:
$kubectl apply -f [File Name.yaml]
當然刪除也可以用.yaml
$kubectl delete -f [File Name.yaml]
YAML file in K8s
YAML有嚴格的空格規定,可以用YAML validator幫忙。分成三部分:
- metadata
- specification
- status(K8s會自動產生)
Demo
用mongo DB和Mongo Express來練習,流程如下:
瀏覽器訪問app網頁
⬇藉由External Service
連接Mongo Express
(check Auth)
將request送到Mongo Express的Pod
⬇藉由ConfigMap(DB Url)
經由Internal Service連到MongoDB
request 送到MongoDB這個Pod
(設定Secret存放DB User、Pwd)
MongoDB settings
設定環境變數
mongo.yaml (Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-deployment
labels:
app: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-password
mongo-secret.yaml(secret)
apiVersion: v1
kind: Secret
metadata:
name: mongodb-secret
type: Opaque
data:
#generate base64 by type below words in terminal
#echo -n "username" | base64
mongo-root-username: dXNlcm5hbWU=
mongo-root-password: cGFzc3dvcmQ=
上面設定完後,到terminal輸入
必須先建立secret,deployment才可以參照!
$kubectl apply -f mongo-secret.yaml
#check
$kubectl get secret
NAME TYPE DATA AGE
mongodb-secret Opaque 2 2m3s
$kubectl apply -f mongo.yaml
Create Internal Service
可以將多個configuration放在同一.yaml中,用---分隔。
mongo.yaml
.
.
.
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-service
spec:
selector:
app: mongodb
ports:
- protocol: TCP
port: 27017
targetPort: 27017
apply
$kubectl apply -f mongo.yaml
#check
$kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17h
mongodb-service ClusterIP 10.96.79.161 <none> 27017/TCP 4s
$kubectl describe service mongodb-service
Name: mongodb-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=mongodb
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.79.161
IPs: 10.96.79.161
Port: <unset> 27017/TCP
TargetPort: 27017/TCP
Endpoints: 172.17.0.2:27017
Session Affinity: None
Events: <none>
see all
$kubectl get all | grep mongodb
pod/mongodb-deployment-67dcfb9c9f-2k8zq 1/1 Running 0 13m
service/mongodb-service ClusterIP 10.96.79.161 <none> 27017/TCP 5m44s
deployment.apps/mongodb-deployment 1/1 1 1 13m
replicaset.apps/mongodb-deployment-67dcfb9c9f 1 1 1 13m
MongoExpress settings
環境變數設定一樣可以從Mongo-Express 的 docker image
找到
Name | Default | Description
--------------------------------|-----------------|------------
ME_CONFIG_BASICAUTH_USERNAME | '' | mongo-express web username
ME_CONFIG_BASICAUTH_PASSWORD | '' | mongo-express web password
ME_CONFIG_MONGODB_ENABLE_ADMIN | 'true' | Enable admin access to all databases. Send strings: `"true"` or `"false"`
ME_CONFIG_MONGODB_ADMINUSERNAME | '' | MongoDB admin username
ME_CONFIG_MONGODB_ADMINPASSWORD | '' | MongoDB admin password
ME_CONFIG_MONGODB_PORT | 27017 | MongoDB port
ME_CONFIG_MONGODB_SERVER | 'mongo' | MongoDB container name. Use comma delimited list of host names for replica sets.
ME_CONFIG_OPTIONS_EDITORTHEME | 'default' | mongo-express editor color theme, [more here](http://codemirror.net/demo/theme.html)
ME_CONFIG_REQUEST_SIZE | '100kb' | Maximum payload size. CRUD operations above this size will fail in [body-parser](https://www.npmjs.com/package/body-parser).
ME_CONFIG_SITE_BASEURL | '/' | Set the baseUrl to ease mounting at a subdirectory. Remember to include a leading and trailing slash.
ME_CONFIG_SITE_COOKIESECRET | 'cookiesecret' | String used by [cookie-parser middleware](https://www.npmjs.com/package/cookie-parser) to sign cookies.
ME_CONFIG_SITE_SESSIONSECRET | 'sessionsecret' | String used to sign the session ID cookie by [express-session middleware](https://www.npmjs.com/package/express-session).
ME_CONFIG_SITE_SSL_ENABLED | 'false' | Enable SSL.
ME_CONFIG_SITE_SSL_CRT_PATH | '' | SSL certificate file.
ME_CONFIG_SITE_SSL_KEY_PATH | '' | SSL key file.
這裡我們需要用到三個變數
如何連到MongoDB?
→ME_CONFIG_MONGODB_SERVER
訪問權限(credential)?
→ME_CONFIG_MONGODB_ADMINUSERNAME
→ME_CONFIG_MONGODB_ADMINPASSWORD
mongo-express.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo-express
labels:
app: mongo-express
spec:
replicas: 1
selector:
matchLabels:
app: mongo-express
template:
metadata:
labels:
app: mongo-express
spec:
containers:
- name: mongo-express
image: mongo-express
ports:
- containerPort: 8081
env:
- name: ME_CONFIG_MONGODB_ADMINUSERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-username
- name: ME_CONFIG_MONGODB_ADMINPASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-password
- name: ME_CONFIG_MONGODB_SERVER
valueFrom:
configMapKeyRef::
name: mongodb-configmap
key: database_url
mongo-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-configmap
data:
database_url: mongodb-service
上面設定完後,到terminal輸入
必須先建立configmap,deployment才可以參照!
$kubectl apply -f mongo-configmap.yaml
$kubectl apply -f mongo-express.yaml
Create External Service
mongo-express.yaml
.
.
.
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-express-service
spec:
selector:
app: mongo-express
# make it external server
type: LoadBalancer
ports:
- protocol: TCP
port: 8081
targetPort: 8081
# make it external server (must between 30000~32767)
nodePort: 30000
terminal
$kubectl apply -f mongo-express.yaml
$kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18h
mongodb-express-service LoadBalancer 10.101.183.184 <pending> 8081:30000/TCP 37s
mongodb-service ClusterIP 10.96.79.161 <none> 27017/TCP 34m
Outcome
$ minikube service mongodb-express-service
|-----------|-------------------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-------------------------|-------------|---------------------------|
| default | mongodb-express-service | 8081 | http://192.168.64.2:30000 |
|-----------|-------------------------|-------------|---------------------------|
🎉 Opening service default/mongodb-express-service in default browser...
Namespace
介紹
概念像是cluster裡面有虛擬的cluster。預設會有4個Namespaces。
$ kubectl get namespaces
NAME STATUS AGE
default Active 10d
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10d
kube-system
不要在此新增或修改任何文件!此處負責system process,例如Master、kubectl的process。
kube-public 存放可公開存取的資料,一configmap用來儲存cluster的資訊。
$ kubectl cluster-info ⏎
Kubernetes control plane is running at https://192.168.64.2:8443
CoreDNS is running at https://192.168.64.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'
kube-node-lease
每一個node都會連到namespace中的lease物件,偵測node的heartbeats(也就是其availability)。
default
最初的resources會放在這,就算使用者沒有自己新增一個namespace。
create new namespaces
with CLI
$ kubectl create namespace my-namespace
namespace/my-namespace created
$ kubectl get namespaces ⏎
NAME STATUS AGE
default Active 11d
kube-node-lease Active 11d
kube-public Active 11d
kube-system Active 11d
my-namespace Active 23s
whit configuration file
apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-configmap
namespace: my-namespace
data:
database_url: mongodb-service
適用案例
Resources grouped in Namespaces
解決 Everything in one namespace ,例如:DB可以是一群、Monitoring也分一群
Many teams, Same application
Resources sharing
- Staging and Development
- Blue/Green Deployment(兩不同版本)
Access and Resources Limits
在同一cluster之間若有兩個以上的projects,建立各自的namespace,限制CPU, RAM, Storage。
幾乎所有東西都不能在不同的Namespace之間共用,而service是可以共用的元素。例如要連到特定DB的app's nod的configmap中,在database_url
指定mysql-service.database
(其中.database
是我們幫存放DB的namespace所取的名字)。
有些components不可以被放進namespace當中,例如volume。用來設定的相關指令是
$ kubectl api-resources --namespaced=false
$ kubectl api-resources --namespaced=true
變更active namespace
若要換到my-namespace這個namespace,就要在每一行kubectl後加上-n my-namespace
。可安裝kubectx內含kubens指令,kubens
代表查看所有namespaces及目前active的那一個;kubens my-namespace
切換active one。
Helm
Package Manager of K8s
Helm Charts : bundle of YAML file,也有Helm Repository放常見的設定檔可供下載。