從K8S部署示例進一步理解容器化編排技術的強大

概念

Kubernetes,也稱為K8s,生產級別的容器編排系統,是一個用於自動化部署、擴展和管理容器化應用程式的開源系統。K8s是一個go語言開發,docker也是go語言開發,可見go語言的是未來的趨勢;從公有雲Iaas、Paas、Saas的雲計算時代開始,到Docker Swarm用於容器化集群和Apache Mesos為分散式資源管理框架,Kubernetes最終打敗其他容器化編排技術成為主流引領者。

kubeadm部署

部署規劃

伺服器最低配置要求: 2core 、2G、 50G,由於需要部署docker,因此如果是centos則要求7以上

所有伺服器的作業系統

cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
主機名 IP
k8s-master2 192.168.50.36
k8s-node-1 192.168.50.34
k8s-node-2 192.168.50.35

網段劃分

名稱 IP網段 備註
service-cluster-ip 10.10.0.0/16 可用地址 65534
pods-ip 10.20.0.0/16 可用地址 65534
集群dns 10.10.0.2 用於集群service域名解析
k8s svc 10.10.0.1 集群 kubernetes svc 解析ip

部署步驟

下面是所有的節點均需操作

#部署docker,找出最新版本 
yum list docker-ce --showduplicates | sort -r
yum list docker-ce-cli --showduplicates | sort -r
#修改為最新的版本
yum -y install docker-ce-20.10.8 docker-ce-cli-20.10.8 containerd.io

#添加/etc/docker/daemon.json內容為
{
"registry-mirrors": ["//b9pmyelo.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重啟docker
systemctl restart docker
systemctl enable docker.service
#關閉防火牆
systemctl stop firewalld # 臨時
systemctl disable firewalld # 永久

#關閉 selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
setenforce 0 # 臨時

#關閉 swap
swapoff -a # 臨時
vim /etc/fstab # 永久

#修改主機名
hostnamectl set-hostname <hostname>

#添加 hosts
cat >> /etc/hosts << EOF
192.168.50.34 k8s-node-1
192.168.50.35 k8s-node-2
192.168.50.36 k8s-master-2
EOF

#使橋接流量對iptables可見,將橋接的 IPv4 流量傳遞到 iptables 的鏈
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

#時間同步
yum install ntpdate -y
ntpdate time.windows.com

# 使用本地軟體包管理軟體安裝 kubectl 二進位文件
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=//mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=//mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg //mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

#安裝 kubeadm,kubelet 和 kubectl
yum install -y kubelet-1.22.1 kubeadm-1.22.1 kubectl-1.22.1
systemctl enable kubelet

image-20210916144804267

查看已安裝版本資訊

image-20210916145124707

kubeadm init --kubernetes-version=1.22.1 \
--apiserver-advertise-address=192.168.50.36 \
--ignore-preflight-errors=all \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.10.0.0/16 \
--pod-network-cidr=10.20.0.0/16

image-20210916160448137

根據上面的提示資訊繼續操作

kubectl get nodesmkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
#下面這段是後面在node節點加入k8s集群的命令
kubeadm join 192.168.50.36:6443 --token jagf90.w67s5swmocymags3 \
	--discovery-token-ca-cert-hash sha256:0afe56b1ca4354bc1148bf25c97e18412ab4f1340d3b62080d1fb1d0901d07c9 
# 如需要重新生成token重新生成加入集群命令可使用下面這個
kubeadm token create --print-join-command
#查看當前集群節點資訊,目前集群的網路還沒有打通,因此狀態為NotReady
kubectl get nodes
#查看當前節點的docker鏡像,kubeadm部署方式是以docker鏡像方式運行集群
docker images

image-20210916163524566

分別在兩台node節點192.168.50.34、192.168.50.35執行加k8s集群的命令

kubeadm join 192.168.50.36:6443 --token jagf90.w67s5swmocymags3 \
	--discovery-token-ca-cert-hash sha256:0afe56b1ca4354bc1148bf25c97e18412ab4f1340d3b62080d1fb1d0901d07c9 

image-20210916165016766

#使kubectl自動補全
source <(kubectl completion bash)
# 查詢目前三個節點的資訊如下
kubectl get nodes
kubectl get pod --all-namespaces -o wide

image-20210916165111924

接下來需要給k8s集群添加CNI網路插件,有很多方式,這裡先提供兩種

#calico網路
kubectl apply -f //docs.projectcalico.org/manifests/calico.yaml          
#或者選擇kube-flannel網路
kubectl apply -f //raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
#過兩分鐘後再查看節點的狀態

image-20210916170305883

image-20210917230153343

image-20210917230304013

通過查找pod的詳細資訊發現問題

#calico.yaml先下載下來
wget //docs.projectcalico.org/manifests/calico.yaml
#calico.yaml增加兩行資訊 - name: IP_AUTODETECTION_METHOD value: "interface=ens.*",interface後面根據實際,我的機器網卡是ens160所以直接填
            # Cluster type to identify the deployment type
            - name: CLUSTER_TYPE
              value: "k8s,bgp"
            - name: IP_AUTODETECTION_METHOD
              value: "interface=ens160"
            # Auto-detect the BGP IP address.
            - name: IP
              value: "autodetect"
#重新應用calico.yaml             
kubectl apply -f calico.yaml  

image-20210917230709263

我們再來解決coredns的ImagePullBackOff的問題

image-20210917230906547

#查看coredns pod的鏡像
kubectl get pods coredns-7f6cbbb7b8-d2rzk -n kube-system -o yaml | grep image    
#顯示資訊如下
    image: registry.aliyuncs.com/google_containers/coredns:v1.8.4
    imagePullPolicy: IfNotPresent
  - image: registry.aliyuncs.com/google_containers/coredns:v1.8.4
    imageID: ""
        message: Back-off pulling image "registry.aliyuncs.com/google_containers/coredns:v1.8.4"
#由於registry.aliyuncs.com/google_containers/coredns:v1.8.4官方是沒有的,官方鏡像是coredns/coredns:1.8.4
#在coredns節點上也即是k8s-node-2也即是192.168.50.35上先下載鏡像
docker pull coredns/coredns:1.8.4
#查看coredns/coredns:1.8.4鏡像的imageid,給鏡像手動打tag為registry.aliyuncs.com/google_containers/coredns:v1.8.4
docker tag 8d147537fb7d registry.aliyuncs.com/google_containers/coredns:v1.8.4

image-20210917231316719

image-20210917231440318

常見幾個問題

1.  加入集群時報錯: /etc/kubernetes/kubelet.conf already exists

原因: 上次的配置文件沒有清理乾淨,刪除即可

rm -rf /etc/kubernetes/kubelet.conf /etc/kubernetes/pki/ca.crt
2.   加入集群時報錯: [ERROR Port-10250]: Port 10250 is in use

原因:上次加入沒有成功就關閉。重置kubeadm

kubeadm reset
 3. 加入集群報錯:/proc/sys/net/ipv4/ip_forward contents are not set to 1

echo "1" >/proc/sys/net/ipv4/ip_forward

容器編排示例

nginx部署示例

所有命令不清楚就是用–help這個萬能的神命令查看,這裡採用deployment部署,當然也可以單獨創建pod,這種在實際場景會比較少用

#創建nginx部署
kubectl create deployment nginx --image=nginx
#暴露埠 type類型可以有多種
kubectl expose deployment nginx --port=80 --type=NodePort
#查看pods和services的資訊,這裡是縮寫,其他縮寫可以查詢--help命令,像上面deployment縮寫為deploy,對應複數可是可以使用,一般使用簡寫
kubectl get pod,svc -o wide

image-20210916173451992

上面有幾個Ip和埠需要理解下。k8s-node-1的ip是192.168.50.34,宿主機上的埠為32173,所以我們可以通過//192.168.50.34:32173 訪問到這個pod暴露的服務

image-20210916173643231

#更新鏡像版本
kubectl set image deploy nginx nginx=nginx:1.7.9
#查看更新狀態
kubectl rollout status deploy nginx
#describe顯示特定資源或資源組的詳細資訊,這裡顯示nginx部署詳細資訊
kubectl describe deploy nginx

image-20210917141923017

#回退到上一次的版本
kubectl rollout undo deploy nginx
#查看deployment變更的對應版本
kubectl rollout history deploy nginx
#查看deployment變更的對應版本的細節
kubectl rollout history deploy nginx --revision=7
#回滾到指定的版本
kubectl rollout undo deploy nginx --to-revision=7

# kubectl proxy主要用於測試,可以通過
kubectl proxy
curl //localhost:8001/api/v1/proxy/namespaces/default/pods/podname訪問

image-20210917151457981

容器擴縮容示例

#擴容nginx pod數量為4
kubectl scale deploy nginx --replicas=4
#查看pod資訊,第一次查詢結果k8s-node-1上pod馬上就有,應該k8s-node-1之前下載了nginx鏡像,第二次k8s-node-2下載完鏡像也啟動兩個pod,k8s有自己的演算法比較均衡將pod分布集群節點上
kubectl get pod -o wide
#縮容nginx pod數量為2,
kubectl scale deploy kubernetes-bootcamp --replicas=2

image-20210917143610845

基於yaml文件方式部署

上面我們都是基於kubectl也即是命令方式直接創建deployment和pod、service,這種方式一般是簡單測試使用,接下來我們基於yaml文件方式部署

編寫單獨創建pod的yaml文件nginx-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.7.9
      ports:
      - containerPort: 80
# 通過create命令用yaml來創建pod,另外還可以使用apply命令用yaml來創建
kubectl create -f nginx-pod.yaml

image-20210917145919844

編寫創建deploy的yaml文件nginx-deploy.yaml,也可以直接通過下面命令生成一個deployment的yaml文件

kubectl create deployment nginx-d1 --image=nginx:1.18 -o yaml --dry-run > nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx-deploment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.18
        name: nginx
        resources: {}
status: {}
#刪除deployment
kubectl delete deploy nginx
# 基於yaml創建deployment
kubectl apply -f nginx-deploy.yaml
#查看labels標籤為app=nginx的pod,上面選擇器為app=nginx,我們創建多個pod,找到label,services也是根據這個label找到然後做負載均衡
kubectl get pods -l app=nginx
#可以查看pod的日誌,和我們之前docker logs一樣
kubectl logs pod -f

image-20210917153236540

接下來我們看下service部分,也即是kubernetes的ingress來暴露應用,創建nginx-service.yaml文件

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 8080
    targetPort: 80
    nodePort: 30080
  selector:
    app: nginx
  type: NodePort

#創建service
kubectl create -f nginx-service.yaml
#查看創建service詳細資訊,安裝完系統有一個名稱為kubernetes的service,這個相當把apiserver做成一個ip
kubectl describe service nginx-service

image-20210917154618381

有幾個重要埠我們一起來了解下

  • nodePort:這個是提供給集群外部的集群訪問的,像這類配置為30080則可以提供給外部訪問,比如這裡直接訪問//192.168.50.34:30080,service內部實現服務發現和負載均衡

image-20210917155331649

  • targetPort:容器的埠,與製作容器鏡像時暴露埠一致,和我們之前學習docker製作dockerfile文件是一樣的,例如我們這裡的測試的nginx,docker.io官方鏡像暴露埠就是80
  • port:這個是kubernetes集群內部各個服務之間互相訪問的埠,比如我們mysql容器雖然暴露3306埠,沒有配置nodePort,外部無法直接訪問容器,但集群內部容器之間是可以通過訪問mysql服務

我們可以進入任意一個容器進行測試,我們進入到kubernetes-bootcamp,然後訪問nginx的pod服務

#由於目前這個容器只有一個pod
kubectl exec -it kubernetes-bootcamp /bin/bash
#如果有多個pod,那就需要通過docker命令找到容器的名稱指定了
kubectl exec -it kubernetes-bootcamp --container xxxxx /bin/bash
#進入一個裝有工具箱的環境,一般用於測試
kubectl run busybox --rm=true --image=busybox --restart=Never --tty -i

image-20210917160859014

生成10.20網段的地址是容器內的地址,10.10網段是用於集群內容通訊的地址,也可以pod直接訪問 ,比如我們這裡的//10.10.11.146

image-20210917175759484

image-20210917175741729

基於dns訪問集群

#查詢所有命名空間的service,kube-dns集群地址為10.10.0.10,這個是kubeadm創建dns服務
kubectl  get svc -A
#如果是手動安裝我們可以通過apply方式部署dns,kube-dns.yaml,下載地址可以網上找,比如//github.com/liuyi01/kubernetes-starter/blob/master/kubernetes-with-ca/services/kube-dns.yaml
kubectl apply -f kube-dns.yaml

image-20210918092423301

可以通過nginx-service名稱訪問到nginx的服務

image-20210918093901511

安裝儀錶盤

# 下載 dashboard.yaml 文件到本地,可以在github kubernetes dashboard項目上查看最新版本,目前U最新版本為v2.3.1
wget //raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
kubectl apply -f recommended.yaml
kubectl proxy

image-20210916175926722

# 設置可以在外部訪問dashboard,修改 dashboard以 nodePort 訪問,編輯配置文件
kubectl -n kubernetes-dashboard edit service kubernetes-dashboard
修改類型
type: ClusterIP 
改為
type: NodePort
#查看暴露的埠
kubectl -n kubernetes-dashboard get service kubernetes-dashboard

image-20210916180136840

通過節點訪問//192.168.50.34:30109/#/login 頁面

image-20210916180556615

在我們上面下載recommended.yaml文件裡面就有subjects,表示創建了 kubernetes-dashbord 賬戶

image-20210917162233195

# 為該賬戶創建登錄 token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard | awk '{print $1}')

Data
====
ca.crt:     1099 bytes
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Im5EOGxxZHFIdnFKeTRabmlicHhRNDVBZ3Y0WlR1enRLQkdoZ21EcFExLWcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi1xenNiayIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjcyNGQ0ODRmLTY2M2YtNGM2YS1hNGMyLTVlOTk3OTliYzczMyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.czIcgip4VJe7dEY_nulArhqKtd2Lc3JGlUrNmn4jGc2ZZ5TMeluRvv71Sztdmb-iYftWKnqil-OuCBgTFss6atShfiQ3__2i4V-vBAM1cFjBtxKZ0QgOpRvDri0hAj34XnF9uSzjH24Gt4x50OX9qaIKmJ8ppHVe0lxBWXP-Z-N4JbrKkRbD6c-EwYBhMoJo7ndUGmkxVsCvuNaE4yRfXENRaunPmGYJMgvFo4XSAz37cznNNVVj8BaIbSxgxv8XPgUEdQZxP2bm2TskVb3AYqeSVd4YR87NxYFod91IezRUBelbupaVWllJVcsEIaANfk4NNN61atWkGO9aNgyK4Q

將上面的token複製,點擊登錄即可

image-20210917163000126