前言
本人之前的實驗環境一直用的是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的管理工具crictl3,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.yamlfile 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
namespace: nfs-server-provisioner
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按其步驟實施即可,本文不再重複描述此過程。
如下所示,這是一個登陸成功後的概況圖:
- crio: ocp/okd默認容器運行時為crio ↩
- error: 本人安裝好k8s後,對於此倉庫後續更新遇到ERROR: The certificate of ‘download.opensuse.org’ is not trusted錯誤,估計系統ca有問題 ↩
- crictl: 此工具作用可用命令
alias docker=crictl來表述 ↩ - crio:默認插件存儲於/etc/cni/net.d/100-crio-bridge.conf目錄 ↩
- metrics: 其是Heapster的輕量化版本,且Heapster早已被廢棄 ↩