前言
本人之前的實驗環境一直用的是OCP/OKD叢集,其搭建在PC Server伺服器上,現需要在自己的windows工作站上搭建一個K8S叢集,首先想到的是使用CodeReady Container(CRC)來搭建一個OKD叢集,但其資源要求實在是太高(4C9G記憶體),且CRC所需的虛擬化軟體hyper-v與virshbox有衝突,鑑於此問題,雖然有minikube可供選擇,但本人決定手動搭建一個原生態K8S叢集。
本人實驗環境為virshbox安裝的一臺虛擬機器,其作業系統版本為Centos Linux 8,CPU 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網路,靜態配置IP為192.168.110.6 |
安裝容器執行時
參考k8s官方文件與cri-o官方文件我們先選擇一容器執行時,如作者對docker容器執行時實在不敢興趣1,故計劃安裝cri-o輕量級容器執行時,參考下圖,作者準備安裝k8s 1.18,故選擇cri-o 1.18.x。
對於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的管理工具crictl
3,kubeadm
會使用其拉取映象。
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.io與k8s.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(網橋)在容器間傳輸流量,亦或者如docker、crio4預設的網路外掛同樣基於網橋傳輸流量,此時需載入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_uuid(
cat /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
接著,執行如下命令安裝kubelet
、kubeadm
、kubectl
,而後設定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.
我們配置的crio的cgroup驅動為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
注意:etcd、kube-apiserver、kube-controller-manager、kube-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.io的Zonefile,然後於其中新增對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對映到叢集外部,其中9000為dashboard埠,8000為http埠,8443為https埠。
$ 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控制檯,其是一個很簡潔的控制檯,可用於檢視一些狀態資訊。
現在,我們為在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,若要在控制檯上顯示Pod的Cpu與Memory資訊,則我們須安裝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按其步驟實施即可,本文不再重複描述此過程。
如下所示,這是一個登陸成功後的概況圖: