k8s實作

操作k8s範例

用Kind創建k8s cluster

  • 假如某個服務器掛了,需要將上面的服務移植到其他服務器

  • 為了部署k8s需要拿一個server當作Control plane

    • 當作主節點master,控制cluster和維護
    • 對k8s進行任務都會經過Control plane
  • 要發送命令會先給Control plane 再發送給Compute machines

  • 一個pod可以部署多個container

  • 每一個Compute machines可以部署多個pod

    • 每一個pod可以部署多個container
    • container 裡面執行我們的應用程式
  • 在只有一台電腦的情況下使用Kind來模擬多服務器

    • 原理就是用docker上的container來模擬多台server
  • k8s中的所有資源接稱為resource,包括pod,service,ingress等等

    • 每一個resource都有一個name
  • k8s支持多個namespace,底下的name不能重複,不使用namespace即為使用default

  • 在高可用情況下會部署多個container plane並在上層增加代理,讓代理先接收資料

    • 多個container plane避免單點故障發生

使用kind部署最小cluster

  • 每個node本質上使用docker模擬
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: dqq
nodes:
  - role: control-plane
  - role: worker
  - role: worker
  • 創建cluster
kind create cluster --config cluster-dqq.yaml
  • 查看cluster狀態
kubectl cluster-info --context kind-dqq

部署服務

  1. 再docker中建立image
docker build -t blog:v1.0.0 ./blog
  1. 將docker上的image導入k8s
kind load docker-image blog:v1.0.0 --name dqq
  1. 部署程式
apiVersion: apps/v1
kind: Deployment
 
# 描述Deployment本身的
metadata:
  name: dep-blog #deploy name
  labels: #可以透過labe選擇resource
    app: blog
 
spec: #詳細描述
  replicas: 2 #副本數量
  selector: # 透過selector選擇resource,讓他被deployment調度
    matchLabels:
      app: blog #假設有兩個pod而他們的label都是app: blog的話,這兩個pod都會被調度,也就是都會有兩個副本
  template: #設定pod的訊息
    # 描述Pod本身的
    metadata:
      labels:
        app: blog #pod的label,這個label會被selector選擇
    spec: #pod的詳細描述
      containers: #pod裡面包含的容器,此為數組,可以有多個pod
        - name: blog #容器名稱
          image: blog:v1.0.0 #容器使用的映像檔
          imagePullPolicy: IfNotPresent #如果映像檔不存在,則拉取映像檔,反之則不進行拉曲
  • 執行k8s命令,會先被control plane接收再分配
kubectl apply -f blog.yaml
  • 獲得pod內容
kubectl get pod
kubectl get pod -o wide #獲得詳細內容

service

  • 現在有個問題是k8s內的服務如果因為錯誤導致pod重啟時,ip也會跟著變動,因此我們需要使用service來固定pod的ip,儘管他遭到刪除等問題后重啟,ip依然不變
apiVersion: v1
kind: Service
 
metadata:
  name: svc-blog
 
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 5678 #外部訪問端口
      targetPort: 5678 #容器內程式開啟端口(原始端口)
      protocol: TCP
  selector:
    app: blog #對應pod的label
  • 使用svc來取代直接訪問pod內部實現了loadbalance

node selector

  • 假設我們有特別的pod希望部署到特殊的server上,可以使用標籤的方式在node上設定標籤
k label nodes dqq-worker hp=true
  • 查看node標籤
k label nodes dqq-worker --list 
  • 當前標籤下node的訊息
k get node -l hp=true             
  • 在創建pod的時候新增node selector,來指定對應node的標籤
apiVersion: apps/v1
kind: Deployment
 
# ...
 
spec:
  replicas: 1 
  template: 
# ...
    metadata:
# ...
      labels: 
      # ...
      nodeSelector:
        hp: "true"
  • 可以發現這一個pod永遠沒辦法調度到node-work2上,因為該node並沒有 hp: "true"這一個標籤

ingress

  • 現在問題是目前部署在k8s的服務都只能從內部訪問
    • 因此使用nginx將服務代理出來

對cluster新增port映射

  • 因為nginx默認開啟的port和當前服務開啟的port不一樣,因此需要新增port mapping
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: dqq
nodes:
  - role: control-plane
    extraPortMappings:
    - containerPort: 80
      hostPort: 80
      protocol: TCP
    - containerPort: 443
      hostPort: 443
      protocol: TCP
  - role: worker
  - role: worker
  • 重新建立cluster
kind delete cluster --name dqq
kind create cluster --config cluster-dqq.yaml
  • 安裝ingrss controller
  • 所有的k8s都可以是一個yaml欓,這邊使用yaml檔進行安裝
    • 會發現其中存在一個nodeSelector,而因為我們希望安裝在control-plane上,因此也需要新增標籤

ingress-controller.yaml

      nodeSelector:
        ingress-ready: "true"
        kubernetes.io/os: linux
  • 新增label
k label nodes dqq-control
  • 安裝ingress-controller
k apply -f ingress-controller.yaml
  • 查看pod情況
    • 因為ingress-controller檔案中都有新增一個namespace
    namespace: ingress-nginx
  • 因此需要指定namespace
k get pod -n ingress-nginx
k get pod -n ingress-nginx -o wide
  • 目前image還沒有加入到新cluster中,因此需要重新加入一次(先前使用docker建立完畢)
kind load docker-image blog:v1.0.0 --name dqq
  • 部署pod到k8s cluster上
k apply -f dep-dqq.yaml
  • 查看pod裡面的訊息
kubectl describe pod <pod-name> -n <namespace>
  • 此時發現錯誤
    • 發現和nodeSelector有關
{node-role.kubernetes.io/control-plane: }, 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling}
  • 將之前在deployment文件裡面的nodeSelector刪除後再重新應用就可以了
  • 因為要能夠被訪問,因此還需要部署service
k appliy -f svc-dqq.yaml
  • 從service查看port
k get svc

配置nginx

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /blog #訪問/blog時實際上會導向service上
        pathType: Prefix
        backend:
          service:
            name: svc-blog
            port:
              number: 5678 #node的port
  • 之後apply後就可以從外部訪問pod了