使用kubeadm搭建一單節點k8s測試叢集

我是讀書人發表於2020-06-12

前言

本人之前的實驗環境一直用的是OCP/OKD叢集,其搭建在PC Server伺服器上,現需要在自己的windows工作站上搭建一個K8S叢集,首先想到的是使用CodeReady Container(CRC)來搭建一個OKD叢集,但其資源要求實在是太高(4C9G記憶體),且CRC所需的虛擬化軟體hyper-vvirshbox有衝突,鑑於此問題,雖然有minikube可供選擇,但本人決定手動搭建一個原生態K8S叢集。

本人實驗環境為virshbox安裝的一臺虛擬機器,其作業系統版本為Centos Linux 8CPU 4個,記憶體4G,磁碟35G,其擁有兩塊網路卡,網路卡1連線到NAT網路以便利用宿主機網路連線英特網,而網路卡2連線到Host-Only網路,K8S API監聽在在此網路上,主機名稱為cts.zyl.io

主機名 主機資源 網路卡1 網路卡2
cts.zyl.io 4C4G、Disk:35G Nat網路,dhcp獲取ip Host-only網路,靜態配置IP192.168.110.6

安裝容器執行時

參考k8s官方文件cri-o官方文件我們先選擇一容器執行時,如作者對docker容器執行時實在不敢興趣1,故計劃安裝cri-o輕量級容器執行時,參考下圖,作者準備安裝k8s 1.18,故選擇cri-o 1.18.x

image.png

對於Centos Linux 8作業系統,執行如下命令安裝CRI-O容器執行時2

sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_8/devel:kubic:libcontainers:stable.repo
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:1.18.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:1.18/CentOS_8/devel:kubic:libcontainers:stable:cri-o:1.18.repo
sudo dnf -y install cri-o

注意:作者當前安裝crio-o 1.18.1時遇到一個bug:檔案/etc/crio/crio.conf中的conmon路徑為 /usr/libexec/crio/conmon,但實際位置在/usr/bin/conmon,於是執行如下命令調整配置後重啟crio程式。

sed 's|/usr/libexec/crio/conmon|/usr/bin/conmon|' -i /etc/crio/crio.conf
systemctl start crio.service

我們安裝crio的管理工具crictl3kubeadm會使用其拉取映象。

wget -O crictl.tgz https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.18.0/crictl-v1.18.0-linux-amd64.tar.gz
tar -xf crictl.tgz
mv crictl /usr/local/bin

如下所示,我們為docker.iok8s.gcr.io配置mirror映象倉庫。注意:為k8s.gcr.io配置映象倉庫很重要,雖然我們可設定--image-repository registry.aliyuncs.com/google_containers來告知kubeinit從阿里雲映象倉庫下載映象,但本人發現部署Pod時仍使用k8s.gcr.io/pause映象,故為了避免因此產生報錯,此處為其配置Mirror映象倉庫。

cat > /etc/containers/registries.conf <<EOF
unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]]
  location = "docker.io"
  insecure = false
  blocked = false
  mirror-by-digest-only = false
  prefix = ""

  [[registry.mirror]]
    location = "docker.mirrors.ustc.edu.cn"
    insecure = false

[[registry]]
  location = "k8s.gcr.io"
  insecure = false
  blocked = false
  mirror-by-digest-only = false
  prefix = ""

  [[registry.mirror]]
    location = "registry.aliyuncs.com/google_containers"
    insecure = false
EOF

參考Network Plugins,當沒有為kubelet配置cni網路外掛時,其使用的noop外掛依賴於Linux bridge(網橋)在容器間傳輸流量,亦或者如dockercrio4預設的網路外掛同樣基於網橋傳輸流量,此時需載入br_netfilter模組並設定net.bridge.bridge-xxx=1以便iptables能識別網橋傳輸的流量。注意:若後續我們選擇的SDN網路不依賴Linux網橋傳輸流量,則此處實際上可忽略,但配置上也沒任何問題。

# these persist across reboots.
cat > /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

# Set up required sysctl params, these persist across reboots.
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system

開始安裝kubeadm

上節已安裝了cri-o容器執行時,本節我們將安裝kubeadm,但在此前,我們參考官方文件Installing kubeadm瞭解一些重要事項,並完善其他所需步驟。

  • 雖然對於本文搭建的單節點叢集來所此處沒任何意義,但為了完整性考慮,我還是記錄於此:檢查叢集各節點,其需具備獨立的主機名稱、MAC地址及product_uuidcat /sys/class/dmi/id/product_uuid);
  • 主機需配置防火牆放行一些埠,為了簡單起見,關閉主機防火牆:
systemctl stop firewalld
systemctl disable firewalld
  • 禁用系統Swap,否則kubeadm會報錯。
cat > /etc/sysctl.d/99-disable-swap.conf <<EOL
vm.swappiness=0
EOL
sysctl --system

vi /etc/fstab      # 註釋swap行
  • 禁用selinux或設定為permissive,否則kubeadm會報錯。
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

接著,執行如下命令安裝kubeletkubeadmkubectl,而後設定kubelet開機自啟動。

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

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

systemctl enable --now kubelet

注意

  • 因網路問題,此處yum源我們選擇阿里雲倉庫,而又因當前無EL8倉庫,故此處只能選擇EL7
  • 此時kubelete會不斷重啟,但這是正常行為,其等待我們執行kubeadm初始化或加入現有k8s叢集。

當前kubeadm僅能為docker容器執行時自動檢測其cgroup driver,而對於我們配置的crio容器執行時,則需要為其手動配置cgroup驅動。

When using Docker, kubeadm will automatically detect the cgroup driver for the kubelet and set it in the /var/lib/kubelet/config.yaml file during runtime.

...

The automatic detection of cgroup driver for other container runtimes like CRI-O and containerd is work in progress.

我們配置的criocgroup驅動為systemd而非cgroupfs,按照官方文件所示需配置/var/lib/kubelet/config.yaml檔案,於其中設定cgroupDriver: systemd

$ cat /etc/crio/crio.conf |grep systemd
cgroup_manager = "systemd"
$ mkdir -p /var/lib/kubelet
$ cat > /var/lib/kubelet/config.yaml <<EOL
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOL
$ systemctl daemon-reload
$ systemctl restart kubelet

但是,這裡有個問題,當執行kubeadm init後不會保留cgroupDriver值,從而導致kubelet呼叫crio容器執行時異常,如下所示。

% journalctl -u kubelet -f
... RunPodSandbox from runtime service failed: rpc error: code = Unknown desc = cri-o configured with systemd cgroup manager, but did not receive slice as parent: /kubepods/besteffort/pod6407b05153e245d7313ea88bfb3be36a

鑑於此,雖然官方文件不建議將引數配置於/etc/sysconfig/kubelet/etc/default/kubelet/var/lib/kubelet/kubeadm-flags.env中,但我們仍然配置於此檔案中:

cat > /etc/sysconfig/kubelet <<EOF
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd
EOF

注意:“安裝容器執行時”一節有提到過,即使我們在呼叫kubeadm init時通過引數--image-repository指定映象倉庫地址,但pause映象仍從k8s.gcr.io獲取從而導致異常,為解決此問題,我們在容器執行時為k8s.gcr.io配置了映象倉庫,但還有一種方式可供選擇:調整kubelet配置指定pause映象。

# /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.2

建立單控制皮膚叢集

參考官方文件Creating a single control-plane cluster with kubeadm,我們執行如下命令建立一個單節點k8s叢集。注意:其中--pod-network-cidr設定的pod網段不應與現有網段重疊,即網段是當前空閒的,因虛擬機器有兩塊網路卡,其預設路由在nat網段上,為了避免叢集api server監控到nat所在的網路卡上,此處通過--apiserver-advertise-address指定apiserver使用host-only所在的網段。

kubeadm init \
    --apiserver-advertise-address=192.168.110.6 \
    --pod-network-cidr=10.254.0.0/16

若命令無報錯,成功後將顯示如下資訊:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.110.6:6443 --token nh1erl.d8eh61epm8s4y8oj \
    --discovery-token-ca-cert-hash sha256:dce7e5ffc2d3d8662ab48bb1a3eae3fff8e0cbf65784295ac01cf631bbfe5ba1 

我們執行如下命令為客戶端工具kubectl配置上下文,其中檔案/etc/kubernetes/admin.conf具備整個叢集管理員許可權。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

那麼此時,我們可通過kubectl檢查叢集狀態了,如下所示:

# 預設建立了4個名稱空間:
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   54m
kube-node-lease   Active   54m
kube-public       Active   54m
kube-system       Active   54m

# k8s系統元件全部至於kube-system名稱空間中
$ kubectl get pod --all-namespaces
NAMESPACE     NAME                                 READY   STATUS    RESTARTS   AGE
kube-system   coredns-66bff467f8-4hfws             1/1     Running   0          55m
kube-system   coredns-66bff467f8-rm5lp             1/1     Running   0          55m
kube-system   etcd-cts.zyl.io                      1/1     Running   0          56m
kube-system   kube-apiserver-cts.zyl.io            1/1     Running   0          56m
kube-system   kube-controller-manager-cts.zyl.io   1/1     Running   0          56m
kube-system   kube-proxy-zcbjj                     1/1     Running   0          55m
kube-system   kube-scheduler-cts.zyl.io            1/1     Running   0          56m

注意etcdkube-apiserverkube-controller-managerkube-scheduler元件為靜態模式部署,其部署清單在主機的/etc/kubernetes/manifests目錄裡,kubelet會自動載入此目錄並啟動pod

$ ls -l /etc/kubernetes/manifests/
-rw------- 1 root root 1858 Jun  8 20:33 etcd.yaml
-rw------- 1 root root 2709 Jun  8 20:33 kube-apiserver.yaml
-rw------- 1 root root 2565 Jun  8 20:33 kube-controller-manager.yaml
-rw------- 1 root root 1120 Jun  8 20:33 kube-scheduler.yaml

coredns使用deployment部署,而kube-proxy使用daemonset模式部署:

$ kubectl get ds,deploy -n kube-system
NAME                        DESIRED           NODE SELECTOR            AGE
daemonset.apps/kube-proxy   1         ...     kubernetes.io/os=linux   60m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   2/2     2            2           60m

coredns部署了兩個pod,對於我們單節點實驗環境來說沒必要,將其設定為1

kubectl scale deployment/coredns --replicas=1 -n kube-system

叢集還缺少SDN網路,我們這裡選擇Calico,其不但具備高效能,且支援網路策略。參考文件Quickstart for Calico on Kubernetes,當系統配置NetworkManager管理網路時,為避免其影響Calico,配置如下檔案告知NM不要管理Calico的網路介面。

cat > /etc/NetworkManager/conf.d/calico.conf <<'EOF'
[keyfile]
unmanaged-devices=interface-name:cali*;interface-name:tunl*
EOF

接著,我們執行如下命令部署Calico注意:除了直接使用部署清單部署calico外,我們還可通過operator部署,專案地址為tigera/operator

kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

執行如下等待其Pod執行正常:

$ watch kubectl get pods -n kube-system
...
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-76d4774d89-bgt86   1/1     Running   0          15m
calico-node-7gjls                          1/1     Running   0          17m

控制節點預設不允許排程Pod,但對於我們的單節點叢集來說,為了測試我們必須要讓控制節點可排程Pod,故執行如下命令放開此限制:

kubectl taint nodes --all node-role.kubernetes.io/master-

K8S叢集部署應用

我們已搭建了一個最基本的K8S叢集,其當前僅含K8S核心控制元件與Calico SDN網路,雖然叢集僅有一個單節點,但因我們配置Master可排程Pod,故此時我們已經可部署測試應用了。

當前我們位於default名稱空間中,執行如下命令快速部署一個nginx

kubectl create deployment nginx --image=nginx

nginx部署僅含一個pod,如下所示:

$ kubectl get pod --show-labels -w
NAME                    READY   STATUS    RESTARTS   AGE   LABELS
nginx-f89759699-lrvzq   1/1     Running   1          15h   app=nginx

獲取其IP地址並訪問:

$ kubectl describe pod -l app=nginx | grep ^IP:
IP:           10.254.40.9
$ curl 10.254.40.9
...
<title>Welcome to nginx!</title>

deployment建立service

$ kubectl expose deploy nginx --port=80 --target-port=80
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx        ClusterIP   10.106.209.139   <none>        80/TCP    34m

配置proxy使用ipvs模式

參考這裡kube-proxy使用ipvs模式在k8s v1.11時已GA,其相對於iptables具備更高的效能,但並不是說iptables就沒有用了,實際上ipvs會與iptables聯合起效。

若我們未執行kubeadm init初始化叢集,則可通過如下方式設定kube-proxy使用ipvs模式:

cat > config.yml <<'EOF'
kubeProxy:
  config:
    featureGates:
      SupportIPVSProxyMode: true
    mode: ipvs
EOF
kube init --config config.yml

對於已經在用的k8s叢集,我們在各節點上執行如下命令載入ipvs模組。注意:本人實驗環境發現下述模組已被自動載入,若如此,則無需處理。

# 動態載入模組
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack

# 確保開機時能載入模組
cat > /etc/modules-load.d/ipvs.conf <<'EOF'
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF

更新configmap,將mode調整為ipvs

$ kubectl edit cm -n kube-system kube-proxy
...
mode: "ipvs"                    # 預設為""(空)則為iptables模式
...

而後重啟kube-proxy,執行如下命令:

kubectl delete pod -n kube-system -l k8s-app=kube-proxy

最後,我們安裝ipvsadm工具並可驗證service已被ipvs所配置。

$ yum -y install ipvsadm
$ ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.96.0.1:443 rr
  -> 192.168.110.6:6443           Masq    1      4          0         
...    

調整叢集CoreDNS配置

對於生產環境,K8S叢集節點主機名應可供DNS域名解析出來,否則可能會因主機名無法被解析而造成某些應用異常,如metrics-server,同樣,對於建立的Ingress所分配的域名,也應被DNS域名系統正確解析,否則我們不得不手動為每個Ingress配置的主機名修改/etc/hosts檔案已做靜態配置。

對於本文搭建的測試環境,我們不在單獨配置額外的DNS域名系統,而是調整K8S叢集的CoreDNS域名系統,如下所示。

參考Custom DNS Entries For Kubernetes文章,我們調整configmap:coredns,於其中新增一個zyl.ioZonefile,然後於其中新增對cts.zyl.io主機的域名解析以及指定.app.zyl.io的一個DNS Wildcard

$ kubectl -n kube-system edit cm coredns
...
  Corefile: |
    .:53 {
    ...
        file /etc/coredns/zone.zyl.io zyl.io
    }
  zone.zyl.io: |
    zyl.io. IN SOA root.zyl.io. root.zyl.io. 2020061113 7200 3600 1W 1D

    cts                IN A  192.168.110.6
    *.app.zyl.io.  300 IN A  192.168.110.6

而後,執行如下命令調整coredns部署,將zone.zyl.io掛載到容器中。

$ kubectl -n kube-system edit deployment coredns
...
      volumes:
      - configMap:
          defaultMode: 420
          items:
          - key: Corefile
            path: Corefile
          - key: zone.zyl.io
            path: zone.zyl.io
          name: coredns
        name: config-volume

接著,啟動一個包含nslookup、host命令的容器進行測試:

$ kubectl run -it --rm --restart=Never --image-pull-policy='IfNotPresent' \
              --image=infoblox/dnstools:latest dnstools
dnstools# host cts
cts.zyl.io has address 192.168.110.6
dnstools# host z.app.zyl.io
z.app.zyl.io has address 192.168.110.6

為了讓叢集外可使用此dns域名系統,我們可將其通過hostNetwork將埠對映出來:

$ kubectl -n kube-system edit deployment coredns
...
      hostNetwork: true
...
$ netstat -an|grep 53|grep udp
udp6       0      0 :::53                   :::*  

安裝附加元件(Add-on

為了完善叢集功能,本章介紹一些基本的附加元件,我們可按需配置,如dashboard對我們測試來說沒啥用,而ingress、持久化儲存比較有用。

通過Ingress使容器可供叢集外訪問

通過Ingress我們可將容器埠對映到叢集外,參考官方文件Ingress Controllers此處我們選擇Traefik控制器。

下面我們使用helm v3來安裝traefik,故我們首先安裝helm v3

wget -O helm.tgz https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
tar -xf helm.tgz
mv linux-amd64/helm /usr/local/bin/
chmod 755 /usr/local/bin/helm

參考專案containous/traefik-helm-chart,執行如下命令將其安裝到獨立的traefik名稱空間中。注意:這裡我們設定hostNetwork=true將埠以主機網路對映到叢集外,而為了訪問dashboard(為了安全原因預設未開放),此處我們設定--api.insecure引數。

helm repo add traefik https://containous.github.io/traefik-helm-chart
cat > /tmp/values.yaml <<EOF
podDisruptionBudget:
  enabled: true

hostNetwork: true

service:
  type: ClusterIP

dashboard:
  ingressRoute: true

ports:
  traefik:
    expose: true

additionalArguments:
  - "--providers.kubernetesingress.ingressclass=traefik"
  - "--log.level=DEBUG"
  - "--api.insecure"
  - "--serverstransport.insecureskipverify=true"
EOF
helm -n traefik install -f /tmp/values.yaml traefik traefik/traefik

上述命令將於traefik名稱空間中安裝如下物件,而埠通過hostNetwork對映到叢集外部,其中9000dashboard埠,8000http埠,8443https埠。

$ kubectl get pod,svc,ingressroute,deployment -n traefik
NAME                           READY   STATUS    RESTARTS   AGE
pod/traefik-7474bbc877-m9c52   1/1     Running   0          2m35s

NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S) ...
service/traefik   ClusterIP   10.111.109.186   <none>        9000/TCP,80/TCP,443/TCP 

NAME                                                 AGE
ingressroute.traefik.containo.us/traefik-dashboard   2m35s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/traefik   1/1     1            1           2m35s

通過主機的9000埠我們開啟dashboard控制檯,其是一個很簡潔的控制檯,可用於檢視一些狀態資訊。

image.png

現在,我們為在default名稱空間中部署的nginx建立一個ingress物件,我們通過註釋kubernetes.io/ingress.class指定由traefik解析。

kubectl -n default apply -f - <<EOF
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: nginx.app.zyl.io
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80
EOF

此處我們設定ingress主機名稱為nginx.app.zyl.io,那麼我們在主機/etc/hosts為其配置一個dns條目指向主機ip地址。

$ cat >> /etc/hosts <<EOF
192.168.110.6 nginx.app.zyl.io
EOF
$ curl nginx.app.zyl.io:8000
...
<title>Welcome to nginx!</title>
...
$ curl 192.168.110.6:8000
404 page not found

快速切換叢集上下文與名稱空間

kubectl每次切換名稱空間均需附帶-n <namespace>引數,對於使用慣了oc命令的使用者來說,這樣實在是太不方便了,幸好有牛人開發了一個ahmetb/kubectx工具,我們可用此來快速切換叢集上下文與名稱空間。

安裝方法有兩種,方法一:通過kubectl外掛包管理工具krew安裝;方法二:手動安裝。

  • 方法1:通過krew安裝外掛方法,參考這裡我們先安裝krew
# 安裝git
yum -y install git

# 安裝krew
(
  set -x; cd "$(mktemp -d)" &&
  curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew.{tar.gz,yaml}" &&
  tar zxvf krew.tar.gz &&
  KREW=./krew-"$(uname | tr '[:upper:]' '[:lower:]')_amd64" &&
  "$KREW" install --manifest=krew.yaml --archive=krew.tar.gz &&
  "$KREW" update
)

# 配置環境變數:
cat > .bashrc <<'EOF'
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
EOF

而後我們執行kubectl krew search驗證krew是否執行,並檢查有哪些plugin可安裝,如下所示:

$ kubectl krew search
NAME                            DESCRIPTION                                         INSTALLED
access-matrix                   Show an RBAC access matrix for server resources     no
advise-psp                      Suggests PodSecurityPolicies for cluster.           no
apparmor-manager                Manage AppArmor profiles for cluster.               no
...

接著,我們執行如下命令安裝ctx(切換context上下文)與ns(切換名稱空間):

kubectl krew install ctx
kubectl krew install ns

安裝完成後,我們則可以外掛方式執行kubectl了,如下所示,我們使用ns快速切換名稱空間。

$ kubectl ns                   #  有哪些namespace
default
kube-node-lease
kube-public
kube-system
traefik

$ kubectl ns traefik           # 切換到traefik名稱空間
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "traefik".

$ kubectl get pod              # 此時已位於traefik名稱空間
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-254tt   1/1     Running   0          130m

$ kubectl ns -                 # 切換回原名稱空間
  • 方法二:手動安裝。
git clone https://github.com/ahmetb/kubectx.git ~/.kubectx
COMPDIR=$(pkg-config --variable=completionsdir bash-completion)
ln -sf ~/.kubectx/completion/kubens.bash $COMPDIR/kubens
ln -sf ~/.kubectx/completion/kubectx.bash $COMPDIR/kubectx
cat << FOE >> ~/.bashrc


#kubectx and kubens
export PATH=~/.kubectx:\$PATH
FOE

如果我們結合fzf則可以互動模式執行上述命令,執行如下命令安裝fzf

# 安裝fzf
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install

配置一個NFS持久化儲存系統

很多場景,我們的應用需要持久化資料,為了簡單考慮,我們選擇使用nfs-server-provisioner搭建一個持久化的NFS儲存系統,此儲存系統一般沒法用於生產,但對於我們測試來說足夠了。

首先,我們需要安裝helm v3而後執行如下命令新增helm倉庫。

$ helm repo add stable https://kubernetes-charts.storage.googleapis.com
"stable" has been added to your repositories

對於作者的單節點K8S叢集,我們需執行如下命令確保如下標籤(labels)值,我們將用其設定部署應用的節點選擇器(nodeSelector)。

% kubectl get node --show-labels
NAME         STATUS   ROLES    AGE   VERSION   LABELS
cts.zyl.io   Ready    master   43h   v1.18.3   kubernetes.io/hostname=cts.zyl.io,...

準備一個/app/nfs/0目錄供本節搭建的nfs服務所用,如作者準備的目錄大小僅10G左右。

mkdir -p /app/nfs/0

建立如下檔案,其中,我們指定將pod排程到cts.zyl.io主機,指定pod副本數為1,為保證nfs提供的儲存卷是持久化的,我們需為nfs server啟用持久化卷(persistence.enabled:true),雖然上面準備的目錄才10G大小,但此處仍可設定超過10G的大小(200Gi),指定建立的儲存卷為預設儲存卷(storageClass.defaultClass:true),這樣若pvc未明確指定storageClass將使用此儲存類。

cat > /tmp/values.yaml <<'EOF'
replicaCount: 1

persistence:
  enabled: true
  storageClass: "-"
  size: 200Gi

storageClass:
  defaultClass: true

nodeSelector:
  kubernetes.io/hostname: cts.zyl.io
EOF

執行如下命令將nfs server部署到一個獨立的名稱空間nfs-server-provisioner中:

kubectl create namespace nfs-server-provisioner
helm -n nfs-server-provisioner install \
     -f /tmp/values.yaml nfs-server-provisioner stable/nfs-server-provisioner

如下所示,部署清單中所需的持久化卷宣告(pvc)此時處於Pending狀態,此時我們為主機的/app/nfs/0建立一個持久化卷(pv),而後關聯到此pvc上。

$ oc get pvc
NAME                            STATUS    VOLUME   CAPACITY   ...
data-nfs-server-provisioner-0   Pending   

$ kubectl -n nfs-server-provisioner create -f - <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: data-nfs-server-provisioner-0
spec:
  capacity:
    storage: 200Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /app/nfs/0
  claimRef:
    kind: PersistentVolumeClaim
    name: data-nfs-server-provisioner-0
EOF

pod啟動完成後,我們可發現叢集上建立了一名為nfs的預設儲存類,主機目錄/app/data/0存在一些檔案。

$ oc get pod
NAME                       READY   STATUS    RESTARTS   AGE
nfs-server-provisioner-0   1/1     Running   0          3s
$ oc get storageclass
NAME            PROVISIONER                            RECLAIMPOLICY  ...
nfs (default)   cluster.local/nfs-server-provisioner   Delete         ...
$ ls /app/nfs/0/
ganesha.log  nfs-provisioner.identity  v4old  v4recov  vfs.conf

最後,讓我們建立一pvc來驗證通過此儲存能為我們自動建立持久化卷pv,換句話說,此儲存類是自動提供的,我們僅宣告需要多大的儲存,而底層儲存卷由儲存系統為我們自動建立好。

$ kubectl -n default create -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
EOF

$ kubectl -n default get pvc
NAME       STATUS   VOLUME                                     CAPACITY   ...
test-pvc   Bound    pvc-ae8f8a8b-9700-494f-ad9f-259345918ec4   10Gi       ...

$ kubectl get pv
NAME               CAPACITY   ACCESS  ... STORAGECLASS
pvc-ae8f8a8b-...   10Gi       RWO     ... nfs

接著,我們執行kubectl -n default delete pvc test-pvc,而後再去觀察pv可發現其被自動釋放了。

安裝K8S原始Dashboard控制檯

本節安裝k8s原生dashboard,這裡使用helm安裝,安裝方法見這裡,首先我們新增helm倉庫:

helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
helm repo add stable https://kubernetes-charts.storage.googleapis.com

參考Kubernetes monitoring architecture,若要在控制檯上顯示PodCpuMemory資訊,則我們須安裝Metrics Server5,但若我們選擇使用coreos/kube-prometheus監控叢集,則可禁用metrics-server,因其已包含了metrics-server的功能。

The kube-prometheus stack includes a resource metrics API server, so the metrics-server addon is not necessary. Ensure the metrics-server addon is disabled on minikube:

這裡我們選擇部署metrics-server,其僅收集叢集核心資料,如資源使用情況,其功能雖沒有coreos/kube-prometheus全,但收集的資料不但可供dashbord用於呈現資源狀態,也可用於基於CPU與記憶體的應用水平擴充套件HPA與應用垂直擴充套件VPA

如下所示,在安裝dashboard前,我們先行將metrics-server安裝到獨立的kube-monitoring名稱空間中,因我們的ca證書是自簽名的,故需要使用--kubelet-insecure-tls啟動metrics-server

kubectl create namespace kube-monitoring
cat > /tmp/values.yaml <<EOF
args:
  - --kubelet-insecure-tls
EOF
helm -n kube-monitoring -f /tmp/values.yaml \
     install metrics-server stable/metrics-server

等待pod啟動成功後,執行如下命令驗證檢查是否可獲取資料。

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
$ kubectl top node
NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
cts.zyl.io   273m         6%     1518Mi          41%      
$ kubectl top pod
NAME                              CPU(cores)   MEMORY(bytes)   
metrics-server-5b6896f6d7-snnbv   3m           13Mi   

開始安裝dashboard,這裡我們啟用metricsScraper,這樣將從metrics-server處獲取效能資料以呈現到控制檯上,而配置ingress使用https實在有點麻煩,為了方便起見這裡使用NodePort將埠對映到叢集外。

kubectl create namespace kube-dashboard
helm -n kube-dashboard install dash \
    --set metricsScraper.enabled=true \
    --set service.type=NodePort  \
    kubernetes-dashboard/kubernetes-dashboard

如下所示NodePort模式所分配的主機埠為30808,故我們可通過https://192.168.110.6:30808訪問控制檯。

$ oc get svc
NAME                        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)
dash-kubernetes-dashboard   NodePort   10.108.149.116   <none>        443:30808/TCP

如下所示,兩種登陸控制檯的方法,我們採用Token方式登陸控制檯,獲取Token的步驟參考官方文件Creating sample user按其步驟實施即可,本文不再重複描述此過程。

image.png

如下所示,這是一個登陸成功後的概況圖:

image.png


  1. crio: ocp/okd預設容器執行時為crio
  2. error: 本人安裝好k8s後,對於此倉庫後續更新遇到ERROR: The certificate of ‘download.opensuse.org’ is not trusted錯誤,估計系統ca有問題
  3. crictl: 此工具作用可用命令alias docker=crictl來表述
  4. crio:預設外掛儲存於/etc/cni/net.d/100-crio-bridge.conf目錄
  5. metrics: 其是Heapster的輕量化版本,且Heapster早已被廢棄

相關文章