K8S入門系列之叢集二進位制部署--> master篇(二)
元件版本和配置策略
元件版本
- Kubernetes 1.16.2
- Docker 19.03-ce
- Etcd 3.3.17 https://github.com/etcd-io/etcd/releases/
Flanneld 0.11.0 https://github.com/coreos/flannel/releases/
外掛:
映象倉庫:
docker registry
harbor
主要配置策略
kube-apiserver:
使用 keepalived 和 haproxy 實現 3 節點高可用;
關閉非安全埠 8080 和匿名訪問;
在安全埠 6443 接收 https 請求;
嚴格的認證和授權策略 (x509、token、RBAC);
使用 https 訪問 kubelet、etcd,加密通訊;kube-controller-manager:
3 節點高可用;主備備
關閉非安全埠,在安全埠 10252 接收 https 請求;
使用 kubeconfig 訪問 apiserver 的安全埠;
自動 approve kubelet 證書籤名請求 (CSR),證書過期後自動輪轉;
各 controller 使用自己的 ServiceAccount 訪問 apiserver;kube-scheduler:
3 節點高可用;主備備kubelet:
使用 kubeadm 動態建立 bootstrap token,也可以在 apiserver 中靜態配置;
使用 TLS bootstrap 機制自動生成 client 和 server 證書,過期後自動輪轉;
在 KubeletConfiguration 型別的 JSON 檔案配置主要引數;
關閉只讀埠,在安全埠 10250 接收 https 請求,對請求進行認證和授權,拒絕匿名訪問和非授權訪問;
使用 kubeconfig 訪問 apiserver 的安全埠;kube-proxy:
使用 kubeconfig 訪問 apiserver 的安全埠;
使用 ipvs 代理模式;叢集外掛:
1. 系統初始化
1.01 系統環境&&基本環境配置
[root@localhost ~]# uname -a
Linux localhost.localdomain 4.18.0-80.11.2.el8_0.x86_64 #1 SMP Tue Sep 24 11:32:19 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost ~]# cat /etc/redhat-release
CentOS Linux release 8.0.1905 (Core)
1.02 修改各個節點的對應hostname, 並分別寫入/etc/hosts
hostnamectl set-hostname k8s-master01
...
# 寫入hosts--> 注意是 >> 表示不改變原有內容追加!
cat>> /etc/hosts <<EOF
192.168.2.201 k8s-master01
192.168.2.202 k8s-master02
192.168.2.203 k8s-master03
192.168.2.11 k8s-node01
192.168.2.12 k8s-node02
EOF
1.03 安裝依賴包和常用工具
yum install wget vim yum-utils net-tools tar chrony curl jq ipvsadm ipset conntrack iptables sysstat libseccomp -y
1.04 所有節點關閉firewalld, dnsmasq, selinux以及swap
# 關閉防火牆並清空防火牆規則
systemctl disable firewalld && systemctl stop firewalld && systemctl status firewalld
iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
iptables -P FORWARD ACCEP
# 關閉dnsmasq否則可能導致docker容器無法解析域名!(centos8不存在!)
systemctl disable --now dnsmasq
# 關閉selinux --->selinux=disabled 需重啟生效!
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
# 關閉swap --->註釋掉swap那一行, 需重啟生效!
swapoff -a && sed -i '/ swap / s/^\(.*\)$/# \1/g' /etc/fstab
1.05 所有節點設定時間同步
timedatectl set-timezone Asia/Shanghai
timedatectl set-local-rtc 0
yum install chrony -y
systemctl enable chronyd && systemctl start chronyd && systemctl status chronyd
1.06 調整核心引數, k8s必備引數!
# 先載入模組
modprobe br_netfilter
cat> kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ipt6ables=1
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max = 6553500
net.nf_conntrack_max = 6553500
net.ipv4.tcp_max_tw_buckets = 4096
EOF
- net.bridge.bridge-nf-call-iptables=1 二層的網橋在轉發包時也會被iptables的FORWARD規則所過濾
- net.ipv6.conf.all.disable_ipv6=1 禁用整個系統所有的ipv6介面, 預防觸發docker的bug
- net.netfilter.nf_conntrack_max 這個預設值是65535,當伺服器上的連線超過這個數的時候,系統會將資料包丟掉,直到小於這個值或達到過期時間net.netfilter.nf_conntrack_tcp_timeout_established,預設值432000,5天。期間的資料包都會丟掉。
- net.ipv4.tcp_max_tw_buckets 這個預設值18000,伺服器TIME-WAIT狀態套接字的數量限制,如果超過這個數量, 新來的TIME-WAIT套接字會直接釋放。過多的TIME-WAIT影響伺服器效能,根據服務自行設定.
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf
1.07 所有節點建立k8s工作目錄並設定環境變數!
# 在每臺機器上建立目錄:
mkdir -p /opt/k8s/{bin,cert,script,kube-apiserver,kube-controller-manager,kube-scheduler,kubelet,kube-proxy}
mkdir -p /opt/etcd/{bin,cert}
mkdir -p /opt/lib/etcd
mkdir -p /opt/flanneld/{bin,cert}
mkdir -p /var/log/kubernetes
# 在每臺機器上新增環境變數:
sh -c "echo 'PATH=/opt/k8s/bin:/opt/etcd/bin:/opt/flanneld/bin:$PATH:$HOME/bin:$JAVA_HOME/bin' >> /etc/profile.d/k8s.sh"
source /etc/profile.d/k8s.sh
1.08 無密碼 ssh 登入其它節點(為了部署方便!!!)
生成祕鑰對
[root@k8s-master01 ~]# ssh-keygen
將自己的公鑰發給其他伺服器
[root@k8s-master01 ~]# ssh-copy-id root@k8s-master01
[root@k8s-master01 ~]# ssh-copy-id root@k8s-master02
[root@k8s-master01 ~]# ssh-copy-id root@k8s-master03
2. 建立CA根證書和金鑰
- 為確保安全, kubernetes 系統各元件需要使用 x509 證書對通訊進行加密和認證。
- CA (Certificate Authority) 是自簽名的根證書,用來簽名後續建立的其它證書。
2.01 安裝cfssl工具集
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@k8s-master01 ~]# mv cfssl_linux-amd64 /opt/k8s/bin/cfssl
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@k8s-master01 ~]# mv cfssljson_linux-amd64 /opt/k8s/bin/cfssljson
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@k8s-master01 ~]# mv cfssl-certinfo_linux-amd64 /opt/k8s/bin/cfssl-certinfo
chmod +x /opt/k8s/bin/*
2.02 建立根證書CA
- CA 證書是叢集所有節點共享的,只需要建立一個CA證書,後續建立的所有證書都由它簽名。
2.02.01 建立配置檔案
- CA 配置檔案用於配置根證書的使用場景 (profile) 和具體引數 (usage,過期時間、服務端認證、客戶端認證、加密等),後續在簽名其它證書時需要指定特定場景。
[root@k8s-master01 ~]# cd /opt/k8s/cert/
[root@k8s-master01 cert]# cat> ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "876000h"
}
}
}
}
EOF
- signing :表示該證書可用於簽名其它證書,生成的 ca.pem 證書中CA=TRUE;
- server auth :表示 client 可以用該該證書對 server 提供的證書進行驗證;
- client auth :表示 server 可以用該該證書對 client 提供的證書進行驗證;
2.02.02 建立證書籤名請求檔案
[root@k8s-master01 cert]# cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "steams"
}
]
}
EOF
- CN: Common Name ,kube-apiserver 從證書中提取該欄位作為請求的使用者名稱(User Name),瀏覽器使用該欄位驗證網站是否合法;
- O: Organization ,kube-apiserver 從證書中提取該欄位作為請求使用者所屬的組(Group);
- kube-apiserver 將提取的 User、Group 作為 RBAC 授權的使用者標識;
2.02.03 生成CA證書和金鑰
[root@k8s-master01 cert]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# 檢視是否生成!
[root@k8s-master01 cert]# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
2.02.04 分發證書檔案
- 簡單指令碼, 注意傳參! 後期想寫整合指令碼的話可以拿來用!
- 將生成的 CA 證書、祕鑰檔案、配置檔案拷貝到所有節點的/opt/k8s/cert 目錄下:
[root@k8s-master01 cert]# vi /opt/k8s/script/scp_k8s_cacert.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/k8s/cert/ca*.pem /opt/k8s/cert/ca-config.json root@${master_ip}:/opt/k8s/cert
done
[root@k8s-master01 cert]# bash /opt/k8s/script/scp_k8s_cacert.sh 192.168.2.201 192.168.2.202 192.168.2.203
3. 部署etcd叢集
- etcd 是基於Raft的分散式key-value儲存系統,由CoreOS開發,常用於服務發現、共享配置以及併發控制(如leader選舉、分散式鎖等)
- kubernetes 使用 etcd 儲存所有執行資料。所以部署三節點高可用!
3.01 下載二進位制檔案
[root@k8s-master01 ~]# wget https://github.com/etcd-io/etcd/releases/download/v3.3.17/etcd-v3.3.17-linux-amd64.tar.gz
[root@k8s-master01 ~]# tar -xvf etcd-v3.3.17-linux-amd64.tar.gz
3.02 建立etcd證書和金鑰
- etcd叢集要與k8s-->apiserver通訊, 所以需要用證書籤名驗證!
3.02.01 建立證書籤名請求
[root@k8s-master01 cert]# cat > /opt/etcd/cert/etcd-csr.json <<EOF
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.2.201",
"192.168.2.202",
"192.168.2.203"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "steams"
}
]
}
EOF
- hosts 欄位指定授權使用該證書的 etcd 節點 IP 或域名列表,這裡將 etcd 叢集的三個節點 IP 都列在其中
3.02.02 生成證書和私鑰
[root@k8s-master01 ~]# cfssl gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes /opt/etcd/cert/etcd-csr.json | cfssljson -bare /opt/etcd/cert/etcd
# 檢視是否生成!
[root@k8s-master01 ~]# ls /opt/etcd/cert/*
etcd.csr etcd-csr.json etcd-key.pem etcd.pem
3.02.03 分發生成的證書, 私鑰和etcd安裝檔案到各etcd節點
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_etcd.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /root/etcd-v3.3.17-linux-amd64/etcd* root@${master_ip}:/opt/etcd/bin
ssh root@${master_ip} "chmod +x /opt/etcd/bin/*"
scp /opt/etcd/cert/etcd*.pem root@${master_ip}:/opt/etcd/cert/
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_etcd.sh 192.168.2.201 192.168.2.202 192.168.2.203
3.03 建立etcd的systemd unit模板及etcd配置檔案
建立etcd的systemd unit模板
[root@k8s-master01 ~]# vi /opt/etcd/etcd.service.template
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos
[Service]
User=root
Type=notify
WorkingDirectory=/opt/lib/etcd/
ExecStart=/opt/etcd/bin/etcd \
--data-dir=/opt/lib/etcd \
--name ##ETCD_NAME## \
--cert-file=/opt/etcd/cert/etcd.pem \
--key-file=/opt/etcd/cert/etcd-key.pem \
--trusted-ca-file=/opt/k8s/cert/ca.pem \
--peer-cert-file=/opt/etcd/cert/etcd.pem \
--peer-key-file=/opt/etcd/cert/etcd-key.pem \
--peer-trusted-ca-file=/opt/k8s/cert/ca.pem \
--peer-client-cert-auth \
--client-cert-auth \
--listen-peer-urls=https://##MASTER_IP##:2380 \
--initial-advertise-peer-urls=https://##MASTER_IP##:2380 \
--listen-client-urls=https://##MASTER_IP##:2379,http://127.0.0.1:2379 \
--advertise-client-urls=https://##MASTER_IP##:2379 \
--initial-cluster-token=etcd-cluster-0 \
--initial-cluster=etcd0=https://192.168.2.201:2380,etcd1=https://192.168.2.202:2380,etcd2=https://192.168.2.203:2380 \
--initial-cluster-state=new
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
- 本示例用指令碼替換變數-->##ETCD_NAME##, ##MASTER_IP##
- WorkingDirectory 、 --data-dir:指定工作目錄和資料目錄為/opt/lib/etcd ,需在啟動服務前建立這個目錄;
- --name :指定各個節點名稱,當 --initial-cluster-state 值為new時, --name的引數值必須位於--initial-cluster 列表中;
- --cert-file 、 --key-file:etcd server 與 client 通訊時使用的證書和私鑰;
- --trusted-ca-file:簽名 client 證書的 CA 證書,用於驗證 client 證書;
- --peer-cert-file 、 --peer-key-file:etcd 與 peer 通訊使用的證書和私鑰;
- --peer-trusted-ca-file:簽名 peer 證書的 CA 證書,用於驗證 peer 證書;
3.04 為各節點建立和分發etcd systemd unit檔案
[root@k8s-master01 ~]# vi /opt/k8s/script/etcd_service.sh
ETCD_NAMES=("etcd0" "etcd1" "etcd2")
MASTER_IPS=("$1" "$2" "$3")
#替換模板檔案中的變數,為各節點建立systemd unit檔案
for (( i=0; i < 3; i++ ));do
sed -e "s/##ETCD_NAME##/${ETCD_NAMES[i]}/g" -e "s/##MASTER_IP##/${MASTER_IPS[i]}/g" /opt/etcd/etcd.service.template > /opt/etcd/etcd-${MASTER_IPS[i]}.service
done
#分發生成的systemd unit和etcd的配置檔案:
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/etcd/etcd-${master_ip}.service root@${master_ip}:/etc/systemd/system/etcd.service
done
[root@k8s-master01 ~]# bash /opt/k8s/script/etcd_service.sh 192.168.2.201 192.168.2.202 192.168.2.203
3.05 啟動etcd服務
[root@k8s-master01 ~]# vi /opt/k8s/script/etcd.sh
MASTER_IPS=("$1" "$2" "$3")
#啟動 etcd 服務
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable etcd && systemctl start etcd"
done
#檢查啟動結果,確保狀態為 active (running)
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
ssh root@${master_ip} "systemctl status etcd|grep Active"
done
#驗證服務狀態,輸出均為healthy 時表示叢集服務正常
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
ETCDCTL_API=3 /opt/etcd/bin/etcdctl \
--endpoints=https://${master_ip}:2379 \
--cacert=/opt/k8s/cert/ca.pem \
--cert=/opt/etcd/cert/etcd.pem \
--key=/opt/etcd/cert/etcd-key.pem endpoint health
done
[root@k8s-master01 ~]# bash /opt/k8s/script/etcd.sh 192.168.2.201 192.168.2.202 192.168.2.203
4. 部署flannel網路
- kubernetes要求叢集內各節點(包括master節點)能通過Pod網段互聯互通。flannel使用vxlan技術為各節點建立一個可以互通的Pod網路,使用的埠為UDP 8472,需要開放該埠(如公有云 AWS 等)。
- flannel第一次啟動時,從etcd獲取Pod網段資訊,為本節點分配一個未使用的 /24段地址,然後建立 flannel.1(也可能是其它名稱) 介面。
- flannel將分配的Pod網段資訊寫入/run/flannel/docker檔案,docker後續使用這個檔案中的環境變數設定docker0網橋。
4.01 下載flannel二進位制檔案
[root@k8s-master01 ~]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
[root@k8s-master01 ~]# mkdir flanneld
[root@k8s-master01 ~]# tar -xvf flannel-v0.11.0-linux-amd64.tar.gz -C flanneld
4.02 建立flannel證書和金鑰
- flannel從etcd叢集存取網段分配資訊,而etcd叢集啟用了雙向x509證書認證,所以需要flanneld 生成證書和私鑰。
4.02.01 建立證書籤名請求
[root@k8s-master01 ~]# cat > /opt/flanneld/cert/flanneld-csr.json <<EOF
{
"CN": "flanneld",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "steams"
}
]
}
EOF
- 該證書只會被 kubectl 當做 client 證書使用,所以 hosts 欄位為空;
4.02.02 生成證書和金鑰
[root@k8s-master01 ~]# cfssl gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes /opt/flanneld/cert/flanneld-csr.json | cfssljson -bare /opt/flanneld/cert/flanneld
[root@k8s-master01 ~]# ll /opt/flanneld/cert/flanneld*
flanneld.csr flanneld-csr.json flanneld-key.pem flanneld.pem
4.02.03 將flanneld二進位制檔案和生成的證書和私鑰分發到所有節點(包含node節點!)
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_flanneld.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /root/flanneld/flanneld /root/flanneld/mk-docker-opts.sh root@${master_ip}:/opt/flanneld/bin/
ssh root@${master_ip} "chmod +x /opt/flanneld/bin/*"
scp /opt/flanneld/cert/flanneld*.pem root@${master_ip}:/opt/flanneld/cert
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_flanneld.sh 192.168.2.201 192.168.2.202 192.168.2.203
4.03 向etcd 寫入叢集Pod網段資訊
- flanneld當前版本(v0.11.0)不支援etcd v3,故需使用etcd v2 API寫入配置key和網段資料;
- 特別注意etcd版本匹配!!!
向etcd 寫入叢集Pod網段資訊(一個節點操作就可以了!)
[root@k8s-master01 ~]# ETCDCTL_API=2 etcdctl \
--endpoints="https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379" \
--ca-file=/opt/k8s/cert/ca.pem \
--cert-file=/opt/flanneld/cert/flanneld.pem \
--key-file=/opt/flanneld/cert/flanneld-key.pem \
set /atomic.io/network/config '{"Network":"10.30.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}'
# 返回如下資訊(寫入的Pod網段"Network"必須是/16 段地址,必須與kube-controller-manager的--cluster-cidr引數值一致)
{"Network":"10.30.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}
4.04 建立flanneld的systemd unit檔案
[root@k8s-master01 ~]# vi /opt/flanneld/flanneld.service.template
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service
[Service]
Type=notify
ExecStart=/opt/flanneld/bin/flanneld \
-etcd-cafile=/opt/k8s/cert/ca.pem \
-etcd-certfile=/opt/flanneld/cert/flanneld.pem \
-etcd-keyfile=/opt/flanneld/cert/flanneld-key.pem \
-etcd-endpoints=https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379 \
-etcd-prefix=/atomic.io/network \
-iface=eth0
ExecStartPost=/opt/flanneld/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure
[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
- mk-docker-opts.sh指令碼將分配給flanneld的Pod子網網段資訊寫入/run/flannel/docker檔案,後續docker啟動時使用這個檔案中的環境變數配置docker0 網橋;
- flanneld使用系統預設路由所在的介面與其它節點通訊,對於有多個網路介面(如內網和公網)的節點,可以用-iface引數指定通訊介面,如上面的eth1介面;
- flanneld 執行時需要 root 許可權;
4.05 分發flanneld systemd unit檔案到所有節點,啟動並檢查flanneld服務
[root@k8s-master01 ~]# vi /opt/k8s/script/flanneld_service.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
#分發 flanneld systemd unit 檔案到所有節點
scp /opt/flanneld/flanneld.service.template root@${master_ip}:/etc/systemd/system/flanneld.service
#啟動 flanneld 服務
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
#檢查啟動結果
ssh root@${master_ip} "systemctl status flanneld|grep Active"
done
[root@k8s-master01 ~]# bash /opt/k8s/script/flanneld_service.sh 192.168.2.201 192.168.2.202 192.168.2.203
4.06 檢查分配給各 flanneld 的 Pod 網段資訊
# 檢視叢集 Pod 網段(/16)
[root@k8s-master01 ~]# ETCDCTL_API=2 etcdctl \
--endpoints="https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379" \
--ca-file=/opt/k8s/cert/ca.pem \
--cert-file=/opt/flanneld/cert/flanneld.pem \
--key-file=/opt/flanneld/cert/flanneld-key.pem \
get /atomic.io/network/config
# 輸出:
{"Network":"10.30.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}
# 檢視已分配的 Pod 子網段列表(/24)
[root@k8s-master01 ~]# ETCDCTL_API=2 etcdctl \
--endpoints="https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379" \
--ca-file=/opt/k8s/cert/ca.pem \
--cert-file=/opt/flanneld/cert/flanneld.pem \
--key-file=/opt/flanneld/cert/flanneld-key.pem \
ls /atomic.io/network/subnets
# 輸出:
/atomic.io/network/subnets/10.30.34.0-24
/atomic.io/network/subnets/10.30.41.0-24
/atomic.io/network/subnets/10.30.7.0-24
# 檢視某一 Pod 網段對應的節點 IP 和 flannel 介面地址
[root@k8s-master01 ~]# ETCDCTL_API=2 etcdctl \
--endpoints="https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379" \
--ca-file=/opt/k8s/cert/ca.pem \
--cert-file=/opt/flanneld/cert/flanneld.pem \
--key-file=/opt/flanneld/cert/flanneld-key.pem \
get /atomic.io/network/subnets/10.30.34.0-24
# 輸出:
{"PublicIP":"192.168.2.202","BackendType":"vxlan","BackendData":{"VtepMAC":"e6:b2:85:07:9f:c0"}}
# 驗證各節點能通過 Pod 網段互通, 注意輸出的pod網段!
[root@k8s-master01 ~]# vi /opt/k8s/script/ping_flanneld.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
#在各節點上部署 flannel 後,檢查是否建立了 flannel 介面(名稱可能為 flannel0、flannel.0、flannel.1 等)
ssh ${master_ip} "/usr/sbin/ip addr show flannel.1|grep -w inet"
#在各節點上 ping 所有 flannel 介面 IP,確保能通
ssh ${master_ip} "ping -c 1 10.30.34.0"
ssh ${master_ip} "ping -c 1 10.30.41.0"
ssh ${master_ip} "ping -c 1 10.30.7.0"
done
# 執行!
[root@k8s-master01 ~]# bash /opt/k8s/script/ping_flanneld.sh 192.168.2.201 192.168.2.202 192.168.2.203
5. 部署kubectl命令列工具
- kubectl 是 kubernetes 叢集的命令列管理工具
- kubectl 預設從 ~/.kube/config 檔案讀取 kube-apiserver 地址、證書、使用者名稱等資訊,如果沒有配置,執行 kubectl 命令時可能會出錯:
- 本文件只需要部署一次,生成的 kubeconfig 檔案與機器無關。
5.01 下載kubectl二進位制檔案, 並分發所有節點(包含node!)
- kubernetes-server-linux-amd64.tar.gz包含所有元件!
[root@k8s-master01 ~]# wget https://dl.k8s.io/v1.16.2/kubernetes-server-linux-amd64.tar.gz
[root@k8s-master01 ~]# tar -zxvf kubernetes-server-linux-amd64.tar.gz
[root@k8s-master01 ~]# vi /opt/k8s/script/kubectl_environment.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /root/kubernetes/server/bin/kubectl root@${master_ip}:/opt/k8s/bin/
done
[root@k8s-master01 ~]# bash /opt/k8s/script/kubectl_environment.sh 192.168.2.201 192.168.2.202 192.168.2.203
5.02 建立 admin 證書和私鑰
- kubectl 與 apiserver https 安全埠通訊,apiserver 對提供的證書進行認證和授權。
- kubectl 作為叢集的管理工具,需要被授予最高許可權。這裡建立具有最高許可權的admin 證書。
建立證書籤名請求
[root@k8s-master01 ~]# cat > /opt/k8s/cert/admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "steams"
}
]
}
EOF
- O 為 system:masters ,kube-apiserver 收到該證書後將請求的 Group 設定為system:masters;
- 預定義的 ClusterRoleBinding cluster-admin 將 Group system:masters 與Role cluster-admin 繫結,該 Role 授予所有 API的許可權;
- 該證書只會被 kubectl 當做 client 證書使用,所以 hosts 欄位為空;
生成證書和私鑰
[root@k8s-master01 ~]# cfssl gencert -ca=/opt/k8s/cert/ca.pem \
-ca-key=/opt/k8s/cert/ca-key.pem \
-config=/opt/k8s/cert/ca-config.json \
-profile=kubernetes /opt/k8s/cert/admin-csr.json | cfssljson -bare /opt/k8s/cert/admin
[root@k8s-master01 ~]# ll /opt/k8s/cert/admin*
admin.csr admin-csr.json admin-key.pem admin.pem
5.03 建立和分發 kubeconfig 檔案
5.03.01 建立kubeconfig檔案
- kubeconfig 為 kubectl 的配置檔案,包含訪問 apiserver 的所有資訊,如 apiserver 地址、CA 證書和自身使用的證書;
step.1 設定叢集引數, --server=${KUBE_APISERVER}, 指定IP和埠; 本文使用的是haproxy的VIP和埠;如果沒有haproxy代理,就用實際服務的IP和埠!
[root@k8s-master01 ~]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/cert/ca.pem \
--embed-certs=true \
--server=https://192.168.2.210:8443 \
--kubeconfig=/root/.kube/kubectl.kubeconfig
step.2 設定客戶端認證引數
[root@k8s-master01 ~]# kubectl config set-credentials kube-admin \
--client-certificate=/opt/k8s/cert/admin.pem \
--client-key=/opt/k8s/cert/admin-key.pem \
--embed-certs=true \
--kubeconfig=/root/.kube/kubectl.kubeconfig
step.3 設定上下文引數
[root@k8s-master01 ~]# kubectl config set-context kube-admin@kubernetes \
--cluster=kubernetes \
--user=kube-admin \
--kubeconfig=/root/.kube/kubectl.kubeconfig
step.4設定預設上下文
[root@k8s-master01 ~]# kubectl config use-context kube-admin@kubernetes --kubeconfig=/root/.kube/kubectl.kubeconfig
--certificate-authority :驗證 kube-apiserver 證書的根證書;
--client-certificate 、 --client-key :剛生成的 admin 證書和私鑰,連線 kube-apiserver 時使用;
--embed-certs=true :將 ca.pem 和 admin.pem 證書內容嵌入到生成的kubectl.kubeconfig 檔案中(不加時,寫入的是證書檔案路徑);
5.03.02 驗證kubeconfig檔案
[root@k8s-master01 ~]# kubectl config view --kubeconfig=/root/.kube/kubectl.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.2.210:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kube-admin
name: kube-admin@kubernetes
current-context: kube-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kube-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
5.03.03 分發 kubeclt 和kubeconfig 檔案,分發到所有使用kubectl 命令的節點
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_kubectl_config.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /root/kubernetes/server/bin/kubectl root@${master_ip}:/opt/k8s/bin/
ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
scp /root/.kube/kubectl.kubeconfig root@${master_ip}:/root/.kube/config
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_kubectl_config.sh 192.168.2.201 192.168.2.202 192.168.2.203
6. 部署master節點
kubernetes master 節點執行如下元件:
kube-apiserver
kube-scheduler
kube-controller-manager- kube-scheduler 和 kube-controller-manager 可以以叢集模式執行,通過 leader 選舉產生一個工作程序,其它程序處於阻塞模式。
- 對於 kube-apiserver,可以執行多個例項, 但對其它元件需要提供統一的訪問地址,該地址需要高可用。本文件使用 keepalived 和 haproxy 實現 kube-apiserver VIP 高可用和負載均衡。
因為對master做了keepalived高可用,所以3臺伺服器都有可能會升成master伺服器(主master宕機,會有從升級為主);因此所有的master操作,在3個伺服器上都要進行。
下載最新版本的二進位制檔案, 想辦法!!!
[root@k8s-master01 ~]# wget https://dl.k8s.io/v1.16.2/kubernetes-server-linux-amd64.tar.gz
[root@k8s-master01 ~]# wget https://dl.k8s.io/v1.16.2/kubernetes-server-linux-amd64.tar.gz
將二進位制檔案拷貝到所有 master 節點
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_master.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /root/kubernetes/server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler} root@${master_ip}:/opt/k8s/bin/
ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_master.sh 192.168.2.201 192.168.2.202 192.168.2.203
6.01 部署高可用元件
- 本文件講解使用 keepalived 和 haproxy 實現 kube-apiserver 高可用的步驟:
keepalived 提供 kube-apiserver 對外服務的 VIP;
haproxy 監聽 VIP,後端連線所有 kube-apiserver 例項,提供健康檢查和負載均衡功能; - 執行 keepalived 和 haproxy 的節點稱為 LB 節點。由於 keepalived 是一主多備執行模式,故至少兩個 LB 節點。
- 本文件複用 master 節點的三臺機器,haproxy 監聽的埠(8443) 需要與 kube-apiserver的埠 6443 不同,避免衝突。
- keepalived 在執行過程中週期檢查本機的 haproxy 程序狀態,如果檢測到 haproxy 程序異常,則觸發重新選主的過程,VIP 將飄移到新選出來的主節點,從而實現 VIP 的高可用。
- 所有元件(如 kubeclt、apiserver、controller-manager、scheduler 等)都通過 VIP 和haproxy 監聽的 8443 埠訪問 kube-apiserver 服務。
6.01.01 安裝軟體包,配置haproxy 配置檔案
[root@k8s-master01 ~]# yum install keepalived haproxy -y
[root@k8s-master01 ~]# vi /etc/haproxy/haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /var/run/haproxy-admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
nbproc 1
defaults
log global
timeout connect 5000
timeout client 10m
timeout server 10m
listen admin_stats
bind 0.0.0.0:10080
mode http
log 127.0.0.1 local0 err
stats refresh 30s
stats uri /status
stats realm welcome login\ Haproxy
stats auth haproxy:123456
stats hide-version
stats admin if TRUE
listen k8s-master
bind 0.0.0.0:8443
mode tcp
option tcplog
balance source
server 192.168.2.201 192.168.2.201:6443 check inter 2000 fall 2 rise 2 weight 1
server 192.168.2.202 192.168.2.202:6443 check inter 2000 fall 2 rise 2 weight 1
server 192.168.2.203 192.168.2.203:6443 check inter 2000 fall 2 rise 2 weight 1
- haproxy 在 10080 埠輸出 status 資訊;
- haproxy 監聽所有介面的 8443 埠,該埠與環境變數 ${KUBE_APISERVER} 指定的埠必須一致;
- server 欄位列出所有kube-apiserver監聽的 IP 和埠;
6.01.02 在其他伺服器安裝、下發haproxy 配置檔案;並啟動檢查haproxy服務
[root@k8s-master01 ~]# vi /opt/k8s/script/haproxy.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
#安裝haproxy
ssh root@${master_ip} "yum install -y keepalived haproxy"
#下發配置檔案
scp /etc/haproxy/haproxy.cfg root@${master_ip}:/etc/haproxy
#啟動檢查haproxy服務
ssh root@${master_ip} "systemctl restart haproxy"
ssh root@${master_ip} "systemctl enable haproxy.service"
ssh root@${master_ip} "systemctl status haproxy|grep Active"
#檢查 haproxy 是否監聽6443 埠
ssh root@${master_ip} "netstat -lnpt|grep haproxy"
done
[root@k8s-master01 ~]# bash /opt/k8s/script/haproxy.sh 192.168.2.201 192.168.2.202 192.168.2.203
輸出類似:
Active: active (running) since Tue 2019-11-12 01:54:41 CST; 543ms ago
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 4995/haproxy
tcp 0 0 0.0.0.0:10080 0.0.0.0:* LISTEN 4995/haproxy
6.01.03 配置和啟動 keepalived 服務
- keepalived 是一主(master)多備(backup)執行模式,故有兩種型別的配置檔案。
- master 配置檔案只有一份,backup 配置檔案視節點數目而定,對於本文件而言,規劃如下:
master: 192.168.2.201
backup:192.168.2.202、192.168.2.203
在192.168.2.201 master主服務;配置檔案:
[root@k8s-master01 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
router_id keepalived_ha_121
}
vrrp_script check-haproxy {
script "killall -0 haproxy"
interval 5
weight -30
}
vrrp_instance VI-k8s-master {
state MASTER
priority 120 # 第一臺從為110, 以此類推!
dont_track_primary
interface eth0
virtual_router_id 121
advert_int 3
track_script {
check-haproxy
}
virtual_ipaddress {
192.168.2.210
}
}
- 我的VIP 所在的介面nterface 為 eth0;根據自己的情況改變
- 使用 killall -0 haproxy 命令檢查所在節點的 haproxy 程序是否正常。如果異常則將權重減少(-30),從而觸發重新選主過程;
- router_id、virtual_router_id 用於標識屬於該 HA 的 keepalived 例項,如果有多套keepalived HA,則必須各不相同;
在192.168.2.202, 192.168.2.203兩臺backup 服務;配置檔案:
[root@k8s-master02 ~]# vi /etc/keepalived/keepalived.conf
global_defs {
router_id keepalived_ha_122_123
}
vrrp_script check-haproxy {
script "killall -0 haproxy"
interval 5
weight -30
}
vrrp_instance VI-k8s-master {
state BACKUP
priority 110 # 第2臺從為100
dont_track_primary
interface eth0
virtual_router_id 121
advert_int 3
track_script {
check-haproxy
}
virtual_ipaddress {
192.168.2.210
}
}
- priority 的值必須小於 master 的值;兩個從的值也需要不一樣;
開啟keepalived 服務
[root@k8s-master01 ~]# systemctl restart keepalived && systemctl enable keepalived && systemctl status keepalived
[root@k8s-master01 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:15:5d:00:68:05 brd ff:ff:ff:ff:ff:ff
inet 192.168.2.101/24 brd 192.168.2.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168.2.10/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::f726:9d22:2b89:694c/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether aa:43:e5:bb:88:28 brd ff:ff:ff:ff:ff:ff
inet 10.30.34.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::a843:e5ff:febb:8828/64 scope link
valid_lft forever preferred_lft forever
- 在master主伺服器上能看到eth0網絡卡上已經有VIP的IP地址存在
6.01.04 檢視 haproxy 狀態頁面
- 瀏覽器訪問 192.168.2.210:10080/status 地址
6.02 部署 kube-apiserver 元件
下載二進位制檔案
- kubernetes_server 包裡有, 已經解壓到/opt/k8s/bin下
6.02.01 建立 kube-apiserver證書和私鑰
建立證書籤名請求
[root@k8s-master01 ~]# cat > /opt/k8s/cert/kube-apiserver-csr.json <<EOF
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"192.168.2.201",
"192.168.2.202",
"192.168.2.203",
"192.168.2.210",
"10.96.0.1",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "steams"
}
]
}
EOF
- hosts 欄位指定授權使用該證書的 IP 或域名列表,這裡列出了 VIP 、apiserver節點 IP、kubernetes 服務 IP 和域名;
- 域名最後字元不能是 . (如不能為kubernetes.default.svc.cluster.local. ),否則解析時失敗,提示: x509:cannot parse dnsName "kubernetes.default.svc.cluster.local." ;
- 如果使用非 cluster.local 域名,如 opsnull.com ,則需要修改域名列表中的最後兩個域名為: kubernetes.default.svc.opsnull 、 kubernetes.default.svc.opsnull.com
- kubernetes 服務 IP 是 apiserver 自動建立的,一般是 --service-cluster-ip-range 引數指定的網段的第一個IP,後續可以通過如下命令獲取:
kubectl get svc kubernetes
生成證書和私鑰
[root@k8s-master01 ~]# cfssl gencert -ca=/opt/k8s/cert/ca.pem \
-ca-key=/opt/k8s/cert/ca-key.pem \
-config=/opt/k8s/cert/ca-config.json \
-profile=kubernetes /opt/k8s/cert/kube-apiserver-csr.json | cfssljson -bare /opt/k8s/cert/kube-apiserver
[root@k8s-master01 ~]# ll /opt/k8s/cert/kube-apiserver*
kube-apiserver.csr kube-apiserver-csr.json kube-apiserver-key.pem kube-apiserver.pem
6.02.02 建立加密配置檔案
產生一個用來加密Etcd 的 Key:
[root@k8s-master01 ~]# head -c 32 /dev/urandom | base64
# 返回一個key, 每臺master節點需要用一樣的 Key!!!
muqIUutYDd5ARLtsg/W1CYWs3g8Fq9uJO/lDpSsv9iw=
使用這個加密的key,建立加密配置檔案
[root@k8s-master01 ~]# vi encryption-config.yaml
kind: EncryptionConfig
apiVersion: v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: muqIUutYDd5ARLtsg/W1CYWs3g8Fq9uJO/lDpSsv9iw=
- identity: {}
6.02.03 將生成的證書和私鑰檔案、加密配置檔案拷貝到master節點的/opt/k8s目錄下
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_apiserver.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/k8s/cert/kube-apiserver*.pem root@${master_ip}:/opt/k8s/cert/
scp /root/encryption-config.yaml root@${master_ip}:/opt/k8s/
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_apiserver.sh 192.168.2.201 192.168.2.202 192.168.2.203
6.02.04 建立 kube-apiserver 的 systemd unit 模板檔案
[root@k8s-master01 ~]# vi /opt/k8s/kube-apiserver/kube-apiserver.service.template
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
ExecStart=/opt/k8s/bin/kube-apiserver \
--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
--anonymous-auth=false \
--experimental-encryption-provider-config=/opt/k8s/encryption-config.yaml \
--advertise-address=##MASTER_IP## \
--bind-address=##MASTER_IP## \
--insecure-port=0 \
--authorization-mode=Node,RBAC \
--runtime-config=api/all \
--enable-bootstrap-token-auth \
--service-cluster-ip-range=10.96.0.0/16 \
--service-node-port-range=30000-50000 \
--tls-cert-file=/opt/k8s/cert/kube-apiserver.pem \
--tls-private-key-file=/opt/k8s/cert/kube-apiserver-key.pem \
--client-ca-file=/opt/k8s/cert/ca.pem \
--kubelet-client-certificate=/opt/k8s/cert/kube-apiserver.pem \
--kubelet-client-key=/opt/k8s/cert/kube-apiserver-key.pem \
--service-account-key-file=/opt/k8s/cert/ca-key.pem \
--etcd-cafile=/opt/k8s/cert/ca.pem \
--etcd-certfile=/opt/k8s/cert/kube-apiserver.pem \
--etcd-keyfile=/opt/k8s/cert/kube-apiserver-key.pem \
--etcd-servers=https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379 \
--enable-swagger-ui=true \
--allow-privileged=true \
--apiserver-count=3 \
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/var/log/kube-apiserver-audit.log \
--event-ttl=1h \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
- -experimental-encryption-provider-config :啟用加密特性;
- --authorization-mode=Node,RBAC : 開啟 Node 和 RBAC 授權模式,拒絕未授權的請求;
- --enable-admission-plugins :啟用 ServiceAccount 和NodeRestriction ;
- --service-account-key-file :簽名 ServiceAccount Token 的公鑰檔案,kube-controller-manager 的 --service-account-private-key-file 指定私鑰檔案,兩者配對使用;
- --tls-*-file :指定 apiserver 使用的證書、私鑰和 CA 檔案。 --client-ca-file 用於驗證 client (kue-controller-manager、kube-scheduler、kubelet、kube-proxy 等)請求所帶的證書;
- --kubelet-client-certificate 、 --kubelet-client-key :如果指定,則使用 https 訪問 kubelet APIs;需要為證書對應的使用者(上面 kubernetes*.pem 證書的使用者為 kubernetes) 使用者定義 RBAC 規則,否則訪問 kubelet API 時提示未授權;
- --bind-address : 不能為 127.0.0.1 ,否則外界不能訪問它的安全埠6443;
- --insecure-port=0 :關閉監聽非安全埠(8080);
- --service-cluster-ip-range : 指定 Service Cluster IP 地址段;
- --service-node-port-range : 指定 NodePort 的埠範圍;
- --runtime-config=api/all=true : 啟用所有版本的 APIs,如autoscaling/v2alpha1;
- --enable-bootstrap-token-auth :啟用 kubelet bootstrap 的 token 認證;
- --apiserver-count=3 :指定叢集執行模式,多臺 kube-apiserver 會通過 leader選舉產生一個工作節點,其它節點處於阻塞狀態;
6.02.05 為各master節點建立和分發 kube-apiserver的systemd unit檔案; 啟動檢查 kube-apiserver 服務
[root@k8s-master01 ~]# vi /opt/k8s/script/apiserver_service.sh
MASTER_IPS=("$1" "$2" "$3")
#替換模板檔案中的變數,為各節點建立 systemd unit 檔案
for (( i=0; i < 3; i++ ));do
sed "s/##MASTER_IP##/${MASTER_IPS[i]}/" /opt/k8s/kube-apiserver/kube-apiserver.service.template > /opt/k8s/kube-apiserver/kube-apiserver-${MASTER_IPS[i]}.service
done
#啟動並檢查 kube-apiserver 服務
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/k8s/kube-apiserver/kube-apiserver-${master_ip}.service root@${master_ip}:/etc/systemd/system/kube-apiserver.service
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver"
ssh root@${master_ip} "systemctl status kube-apiserver |grep 'Active:'"
done
[root@k8s-master01 ~]# bash /opt/k8s/script/apiserver_service.sh 192.168.2.201 192.168.2.202 192.168.2.203
6.02.06 列印 kube-apiserver 寫入 etcd 的資料
[root@k8s-master01 ~]# ETCDCTL_API=3 etcdctl \
--endpoints="https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379" \
--cacert=/opt/k8s/cert/ca.pem \
--cert=/opt/etcd/cert/etcd.pem \
--key=/opt/etcd/cert/etcd-key.pem \
get /registry/ --prefix --keys-only
6.02.07 檢查叢集資訊
[root@k8s-master01 ~]# kubectl cluster-info
Kubernetes master is running at https://192.168.2.210:8443
[root@k8s-master01 ~]# kubectl get all --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 49m
# 6443: 接收 https 請求的安全埠,對所有請求做認證和授權;
# 由於關閉了非安全埠,故沒有監聽 8080;
[root@k8s-master01 ~]# ss -nutlp |grep apiserver
tcp LISTEN 0 128 192.168.2.201:6443 0.0.0.0:* users:(("kube-apiserver",pid=4425,fd=6))
6.03 部署高可用kube-controller-manager 叢集
- 該叢集包含 3 個節點,啟動後將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用後,剩餘節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。
- 為保證通訊安全,本文件先生成 x509 證書和私鑰,kube-controller-manager 在如下兩種情況下使用該證書:
與 kube-apiserver 的安全埠通訊時;
在安全埠(https,10252) 輸出 prometheus 格式的 metrics;
準備工作:下載kube-controller-manager二進位制檔案(包含在kubernetes-server包裡, 已解壓傳送)
6.03.01 建立 kube-controller-manager 證書和私鑰
建立證書籤名請求:
[root@k8s-master01 ~]# cat > /opt/k8s/cert/kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"192.168.2.201",
"192.168.2.202",
"192.168.2.203"
],
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:kube-controller-manager",
"OU": "steams"
}
]
}
EOF
- hosts 列表包含所有 kube-controller-manager 節點 IP;
- CN 為 system:kube-controller-manager、O 為 system:kube-controller-manager(kubernetes 內建的 ClusterRoleBindings system:kube-controller-manager 賦予kube-controller-manager 工作所需的許可權.)
生成證書和私鑰
cfssl gencert -ca=/opt/k8s/cert/ca.pem \
-ca-key=/opt/k8s/cert/ca-key.pem \
-config=/opt/k8s/cert/ca-config.json \
-profile=kubernetes /opt/k8s/cert/kube-controller-manager-csr.json | cfssljson -bare /opt/k8s/cert/kube-controller-manager
[root@k8s-master01 ~]# ll /opt/k8s/cert/kube-controller-manager*
kube-controller-manager.csr kube-controller-manager-csr.json kube-controller-manager-key.pem kube-controller-manager.pem
6.03.02 建立.kubeconfig 檔案
- kubeconfig 檔案包含訪問 apiserver 的所有資訊,如 apiserver 地址、CA 證書和自身使用的證書;
執行命令,生成kube-controller-manager.kubeconfig檔案
# step.1 設定叢集引數:
[root@k8s-master01 ~]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/cert/ca.pem \
--embed-certs=true \
--server=https://192.168.2.210:8443 \
--kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig
# step.2 設定客戶端認證引數
[root@k8s-master01 ~]# kubectl config set-credentials system:kube-controller-manager \
--client-certificate=/opt/k8s/cert/kube-controller-manager.pem \
--client-key=/opt/k8s/cert/kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig
# step.3 設定上下文引數
[root@k8s-master01 ~]# kubectl config set-context system:kube-controller-manager@kubernetes \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig
# tep.4 設定預設上下文
[root@k8s-master01 ~]# kubectl config use-context system:kube-controller-manager@kubernetes \
--kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig
驗證kube-controller-manager.kubeconfig檔案
[root@k8s-master01 ~]# kubectl config view --kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.2.210:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: system:kube-controller-manager
name: system:kube-controller-manager@kubernetes
current-context: system:kube-controller-manager@kubernetes
kind: Config
preferences: {}
users:
- name: system:kube-controller-manager
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
分發生成的證書和私鑰、kubeconfig 到所有 master 節點
[root@k8s-master01 ~]# vi /opt/k8s/script/scp_controller_manager.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/k8s/cert/kube-controller-manager*.pem root@${master_ip}:/opt/k8s/cert/
scp /opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig root@${master_ip}:/opt/k8s/kube-controller-manager/
done
[root@k8s-master01 ~]# bash /opt/k8s/script/scp_controller_manager.sh 192.168.2.201 192.168.2.202 192.168.2.203
6.03.03 建立和分發 kube-controller-manager 的 systemd unit 檔案
[root@k8s-master01 ~]# vi /opt/k8s/kube-controller-manager/kube-controller-manager.service.template
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/opt/k8s/bin/kube-controller-manager \
--port=0 \
--secure-port=10252 \
--bind-address=127.0.0.1 \
--kubeconfig=/opt/k8s/kube-controller-manager/kube-controller-manager.kubeconfig \
--service-cluster-ip-range=10.96.0.0/16 \
--cluster-name=kubernetes \
--cluster-signing-cert-file=/opt/k8s/cert/ca.pem \
--cluster-signing-key-file=/opt/k8s/cert/ca-key.pem \
--experimental-cluster-signing-duration=8760h \
--root-ca-file=/opt/k8s/cert/ca.pem \
--service-account-private-key-file=/opt/k8s/cert/ca-key.pem \
--leader-elect=true \
--feature-gates=RotateKubeletServerCertificate=true \
--controllers=*,bootstrapsigner,tokencleaner \
--horizontal-pod-autoscaler-use-rest-clients=true \
--horizontal-pod-autoscaler-sync-period=10s \
--tls-cert-file=/opt/k8s/cert/kube-controller-manager.pem \
--tls-private-key-file=/opt/k8s/cert/kube-controller-manager-key.pem \
--use-service-account-credentials=true \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2
Restart=on
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
- --port=0:關閉監聽 http /metrics 的請求,同時 --address 引數無效,--bind-address 引數有效;
- --secure-port=10252、--bind-address=0.0.0.0: 在所有網路介面監聽 10252 埠的 https /metrics 請求;
- --kubeconfig:指定 kubeconfig 檔案路徑,kube-controller-manager 使用它連線和驗證 kube-apiserver;
- --cluster-signing-*-file:簽名 TLS Bootstrap 建立的證書;
- --experimental-cluster-signing-duration:指定 TLS Bootstrap 證書的有效期;
- --root-ca-file:放置到容器 ServiceAccount 中的 CA 證書,用來對 kube-apiserver 的證書進行校驗;
- --service-account-private-key-file:簽名 ServiceAccount 中 Token 的私鑰檔案,必須和 kube-apiserver 的 --service-account-key-file 指定的公鑰檔案配對使用;
- --service-cluster-ip-range :指定 Service Cluster IP 網段,必須和 kube-apiserver 中的同名引數一致;
- --leader-elect=true:叢集執行模式,啟用選舉功能;被選為 leader 的節點負責處理工作,其它節點為阻塞狀態;
- --feature-gates=RotateKubeletServerCertificate=true:開啟 kublet server 證書的自動更新特性;
- --controllers=*,bootstrapsigner,tokencleaner:啟用的控制器列表,tokencleaner 用於自動清理過期的 Bootstrap token;
- --horizontal-pod-autoscaler-*:custom metrics 相關引數,支援 autoscaling/v2alpha1;
- --tls-cert-file、--tls-private-key-file:使用 https 輸出 metrics 時使用的 Server 證書和祕鑰;
- --use-service-account-credentials=true:
6.03.04 kube-controller-manager 的許可權
- ClusteRole: system:kube-controller-manager 的許可權很小,只能建立 secret、serviceaccount 等資源物件,各 controller 的許可權分散到 ClusterRole system:controller:XXX 中。
- 需要在 kube-controller-manager 的啟動引數中新增 --use-service-account-credentials=true 引數,這樣 main controller 會為各 controller 建立對應的 ServiceAccount XXX-controller。
- 內建的 ClusterRoleBinding system:controller:XXX 將賦予各 XXX-controller ServiceAccount 對應的 ClusterRole system:controller:XXX 許可權。
6.03.05 分發systemd unit 檔案到所有master 節點;啟動檢查 kube-controller-manager 服務
[root@k8s-master01 ~]# vi /opt/k8s/script/controller_manager_service.sh
MASTER_IPS=("$1" "$2" "$3")
for master_ip in ${MASTER_IPS[@]};do
echo ">>> ${master_ip}"
scp /opt/k8s/kube-controller-manager/kube-controller-manager.service.template root@${master_ip}:/etc/systemd/system/kube-controller-manager.service
ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl start kube-controller-manager "
ssh root@${master_ip} "systemctl status kube-controller-manager|grep Active"
done
[root@k8s-master01 ~]# bash /opt/k8s/script/controller_manager_service.sh 192.168.2.201 192.168.2.202 192.168.2.203
6.03.6 檢視輸出的 metric
[root@k8s-master01 ~]# ss -nutlp |grep kube-controll
tcp LISTEN 0 128 127.0.0.1:10252 0.0.0.0:* users:(("kube-controller",pid=9382,fd=6))
6.03.07 測試 kube-controller-manager 叢集的高可用
- 停掉一個或兩個節點的 kube-controller-manager 服務,觀察其它節點的日誌,看是否獲取了 leader 許可權。
- 檢視當前的 leader
[root@k8s-master02 ~]# kubectl get endpoints kube-controller-manager --namespace=kube-system -o yaml
6.04 部署高可用 kube-scheduler 叢集
- 該叢集包含 3 個節點,啟動後將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用後,剩餘節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。
- 為保證通訊安全,本文件先生成 x509 證書和私鑰,kube-scheduler 在如下兩種情況下使用該證書:
與 kube-apiserver 的安全埠通訊;
在安全埠(https,10251) 輸出 prometheus 格式的 metrics;
準備工作:下載kube-scheduler 的二進位制檔案---^^^
6.04.01 建立 kube-scheduler 證書和私鑰
建立證書籤名請求:
[root@k8s-master01 ~]# cat > /opt/k8s/cert/kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"hosts": [
"127.0.0.1",
"192.168.2.201