一、項目介紹
項目致力於讓有意向使用原生kubernetes集群的企業或個人,可以方便的、系統的使用二進制的方式手工搭建kubernetes高可用集群。並且讓相關的人員可以更好的理解kubernetes集群的運作機制。
軟件版本
- os centos7.7(ubuntu也適用,需要替換部分命令)
- kubernetes 1.16.2
- etcd 3.4.3
- docker 18.06
- calico 3.10.1-2
- coredns
配置策略
kube-apiserver:
- 使用節點本地 nginx 4 層透明代理實現高可用;
- 關閉非安全端口 8080 和匿名訪問;
- 在安全端口 6443 接收 https 請求;
- 嚴格的認證和授權策略 (x509、token、RBAC);
- 開啟 bootstrap token 認證,支持 kubelet TLS bootstrapping;
- 使用 https 訪問 kubelet、etcd,加密通信;
kube-controller-manager:
- 3 節點高可用;
- 關閉非安全端口 10252,在安全端口 10257 接收 https 請求;
- 使用 kubeconfig 訪問 apiserver 的安全端口;
- 自動 approve kubelet 證書簽名請求 (CSR),證書過期后自動輪轉;
- 各 controller 使用自己的 ServiceAccount 訪問 apiserver;
kube-scheduler:
- 3 節點高可用;
- 關閉非安全端口 10251,在安全端口 10259 接收 https 請求;
- 使用 kubeconfig 訪問 apiserver 的安全端口;
kubelet:
- 使用 kubeadm 動態創建 bootstrap token,而不是在 apiserver 中靜態配置;
- 使用 TLS bootstrap 機制自動生成 client 和 server 證書,過期后自動輪轉;
- 在 KubeletConfiguration 類型的 JSON 文件配置主要參數;
- 關閉只讀端口 10255,在安全端口 10250 接收 https 請求,對請求進行認證和授權,拒絕匿名訪問和非授權訪問;
- 使用 kubeconfig 訪問 apiserver 的安全端口;
kube-proxy:
- 使用 kubeconfig 訪問 apiserver 的安全端口;
- 在 KubeProxyConfiguration 類型的 JSON 文件配置主要參數;
- 使用 ipvs 代理模式;
集群插件:
- DNS:使用功能、性能更好的 coredns;
- Dashboard:支持登錄認證;
- Metric:metrics-server,使用 https 訪問 kubelet 安全端口;
- Log:Elasticsearch、Fluend、Kibana;
- Registry 鏡像庫:docker-registry、harbor;
二、實踐環境准備
1. 服務器說明
我們這里使用的是五台centos 7.7虛擬機,具體信息如下表:
系統類型 | IP地址 | 節點角色 | CPU | Memory | Hostname |
---|---|---|---|---|---|
centos-7.7 | 172.18.0.100 | master | >=2 | >=2G | k8s-m01 |
centos-7.7 | 172.18.0.101 | master | >=2 | >=2G | k8s-m02 |
centos-7.7 | 172.18.0.102 | master | >=2 | >=2G | k8s-m03 |
centos-7.7 | 172.18.0.103 | worker | >=2 | >=2G | k8s-n01 |
centos-7.7 | 172.18.0.104 | worker | >=2 | >=2G | k8s-n02 |
2. 系統設置(所有節點)
2.1 主機名
主機名必須每個節點都不一樣,並且保證所有點之間可以通過 hostname 互相訪問。
# 查看主機名
$ hostname
# 修改主機名
$ hostnamectl set-hostname <your_hostname>
# 配置host,使主節點之間可以通過hostname互相訪問
$ vi /etc/hosts
# <node-ip> <node-hostname>
2.2 安裝依賴包
# 更新yum
$ yum update
# 安裝依賴包
$ yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp wget
## 時間同步
$ ntpdate time1.aliyun.com
2.3 關閉防火牆、swap,重置iptables
# 關閉防火牆
$ systemctl stop firewalld && systemctl disable firewalld
# 重置iptables
$ iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT
# 關閉swap
$ swapoff -a
$ sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
# 關閉selinux
$ setenforce 0
# 關閉dnsmasq(否則可能導致docker容器無法解析域名)
$ service dnsmasq stop && systemctl disable dnsmasq
2.4 系統參數設置
# 制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf
2.5 加載內核模塊
modprobe ip_vs_rr
modprobe br_netfilter
3. 安裝docker(worker節點)
根據kubernetes對docker版本的兼容測試情況,我們選擇18.06版本,我們配置阿里雲的源,速度比較快。
# 添加 yum 源
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -P /etc/yum.repos.d/
# 清理原有版本
yum remove -y docker* container-selinux
# 安裝docker
yum list docker-ce.x86_64 --showduplicates |sort -r
yum install docker-ce-18.06.1.ce -y
# 開機啟動
systemctl enable docker
# 配置加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://hdi5v8p1.mirror.aliyuncs.com"]
}
EOF
# 啟動docker服務
service docker restart
4. 准備二進制文件(所有節點)
4.1 配置免密登錄
為了方便文件的copy我們選擇一個中轉節點(隨便一個節點,可以是集群中的也可以是非集群中的),配置好跟其他所有節點的免密登錄,我們這里使用 k8s-m01。
# 看看是否已經存在rsa公鑰
$ cat ~/.ssh/id_rsa.pub
# 如果不存在就創建一個新的
$ ssh-keygen -t rsa
# 免密鑰認證
$ ssh-copy-id root@<your-server-ip>
4.2 下載二進制文件
官方下載地址(在CHANGELOG鏈接里面):
https://github.com/kubernetes/kubernetes/releases
我們選擇的版本是 1.16.2
。
網盤下載地址--推薦(我從官網下載整理好的文件):
鏈接: https://pan.baidu.com/s/1Ut9VERgm55B4lmz0wjjzFQ
提取碼: mjem
4.3 分發文件
# 把文件copy到每個節點上(注意替換自己的文件目錄)
$ scp master/* <user>@<master-ip>:/usr/local/bin/
$ scp worker/* <user>@<worker-ip>:/usr/local/bin/
# 給文件添加可執行權限
$ chmod +x /usr/local/bin/*
5. 准備配置文件(k8s-m01 節點)
上一步我們下載了kubernetes各個組件的二進制文件,這些可執行文件的運行也是需要添加很多參數的,包括有的還會依賴一些配置文件。現在我們就把運行它們需要的參數和配置文件都准備好。
5.1 下載配置文件
我這准備了一個項目,專門為大家按照自己的環境生成配置的。它只是幫助大家盡量的減少了機械化的重復工作。它並不會幫你設置系統環境,不會給你安裝軟件。總之就是會減少你的部署工作量,但不會耽誤你對整個系統的認識和把控。
$ cd ~
$ git clone https://github.com/wangzan18/kubernetes-ha-binary.git
# 看看git內容
$ ls -l kubernetes-ha-binary
addons/
configs/
pki/
services/
init.sh
global-configs.properties
5.2 文件說明
addons :kubernetes的插件目錄,包括calico、coredns、dashboard等。
configs:這個目錄比較 - 凌亂,包含了部署集群過程中用到的雜七雜八的配置文件、腳本文件等。
pki:各個組件的認證授權相關證書配置。
services:所有的kubernetes服務(service)配置文件。
global-configs.properties:全局配置,包含各種易變的配置內容。
init.sh:初始化腳本,配置好global-config之后,會自動生成所有配置文件。
5.3 生成配置
這里會根據大家各自的環境生成kubernetes部署過程需要的配置文件。
在每個節點上都生成一遍,把所有配置都生成好,后面會根據節點類型去使用相關的配置。
# cd到之前下載的git代碼目錄
$ cd kubernetes-ha-binary
# 編輯屬性配置(根據文件注釋中的說明填寫好每個key-value)
$ vim global-config.properties
# 生成配置文件,確保執行過程沒有異常信息
$ ./init.sh
# 查看生成的配置文件,確保腳本執行成功
$ find target/ -type f
三、高可用集群部署
1. CA證書(任意節點)
1.1 安裝cfssl
cfssl是非常好用的CA工具,我們用它來生成證書和秘鑰文件
安裝過程比較簡單,如下:
# 下載
$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
# 修改為可執行權限
$ chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson
# 驗證
$ cfssl version
Version: 1.2.0
Revision: dev
Runtime: go1.6
1.2 生成根證書
查看證書配置文件,CA 配置文件用於配置根證書的使用場景 (profile) 和具體參數 (usage,過期時間、服務端認證、客戶端認證、加密等),后續在簽名其它證書時需要指定特定場景。
$ cd target/pki/
$ cat ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
signing
:表示該證書可用於簽名其它證書,生成的ca.pem
證書中CA=TRUE
;server auth
:表示 client 可以用該該證書對 server 提供的證書進行驗證;client auth
:表示 server 可以用該該證書對 client 提供的證書進行驗證;
查看證書簽名請求文件。
$ cat ca-csr.json
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "seven"
}
]
}
- CN:
Common Name
,kube-apiserver 從證書中提取該字段作為請求的用戶名 (User Name),瀏覽器使用該字段驗證網站是否合法; - O:
Organization
,kube-apiserver 從證書中提取該字段作為請求用戶所屬的組 (Group); - kube-apiserver 將提取的 User、Group 作為
RBAC
授權的用戶標識;
根證書是集群所有節點共享的,只需要創建一個 CA 證書,后續創建的所有證書都由它簽名。
# 生成證書和私鑰
$ cd target/pki
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# 生成完成后會有以下文件(我們最終想要的就是ca-key.pem和ca.pem,一個秘鑰,一個證書)
$ ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
# 創建目錄
$ ssh <user>@<node-ip> "mkdir -p /etc/kubernetes/pki/"
# 分發到每個matser主節點
$ scp ca*.pem <user>@<master-ip>:/etc/kubernetes/pki/
2. 部署etcd集群(master節點)
2.1 下載etcd,並傳到各master節點
$ wget https://github.com/etcd-io/etcd/releases/download/v3.4.3/etcd-v3.4.3-linux-amd64.tar.gz
$ tar xf etcd-v3.4.3-linux-amd64.tar.gz
$ scp etcd-v3.4.3-linux-amd64/etcd* <user>@<master-ip>:/usr/local/bin/
2.2 生成證書和私鑰
查看證書請求文件。
$ cd target/pki/etcd
$ cat etcd-csr.json
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"172.18.0.100",
"172.18.0.101",
"172.18.0.102"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "seven"
}
]
}
- hosts 字段指定授權使用該證書的 etcd 節點 IP 或域名列表,需要將 etcd 集群的三個節點 IP 都列在其中;
# 生成證書、私鑰
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd
# 分發到每個etcd節點(master節點)
$ scp etcd*.pem <user>@<master-ip>:/etc/kubernetes/pki/
2.3 創建service文件
# scp配置文件到每個master節點
$ scp target/<node-ip>/services/etcd.service <node-ip>:/etc/systemd/system/
# 創建數據和工作目錄
$ ssh <user>@<node-ip> "mkdir -p /var/lib/etcd"
2.4 啟動服務
etcd 進程首次啟動時會等待其它節點的 etcd 加入集群,命令 systemctl start etcd 會卡住一段時間,為正常現象。
#啟動服務
$ systemctl daemon-reload && systemctl enable etcd && systemctl restart etcd
#查看狀態
$ service etcd status
#查看啟動日志
$ journalctl -f -u etcd
#查看服務監聽端口
$ netstat -tlnp |grep etcd
3. 部署api-server(master節點)
3.1 生成證書和私鑰
查看證書請求文件。
$ cd target/pki/apiserver
$ cat kubernetes-csr.json
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"172.18.0.100",
"172.18.0.101",
"172.18.0.102",
"172.18.0.88",
"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": "seven"
}
]
}
# 生成證書、私鑰
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
# 分發到每個master節點
$ scp kubernetes*.pem <user>@<master-ip>:/etc/kubernetes/pki/
3.2 創建后續訪問 metrics-server 使用的證書
創建證書簽名請求:
$ cd target/pki/metrics-server
$ cat > proxy-client-csr.json <<EOF
{
"CN": "aggregator",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "seven"
}
]
}
EOF
- CN 名稱需要位於 kube-apiserver 的
--requestheader-allowed-names
參數中,否則后續訪問 metrics 時會提示權限不足。
生成證書和私鑰:
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client
# 分發到每個master節點
$ scp proxy-client*.pem <user>@<master-ip>:/etc/kubernetes/pki/
3.3 創建service文件
# scp配置文件到每個master節點
$ scp target/<node-ip>/services/kube-apiserver.service <user>@<node-ip>:/etc/systemd/system/
# 創建日志目錄
$ ssh <user>@<node-ip> "mkdir -p /var/log/kubernetes"
# 復制配置文件
$ scp target/configs/encryption-config.yaml <user>@<master-ip>:/etc/kubernetes/
$ scp target/configs/audit-policy.yaml <user>@<master-ip>:/etc/kubernetes/
3.3 啟動服務
#啟動服務
$ systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver
#查看運行狀態
$ service kube-apiserver status
#查看日志
$ journalctl -f -u kube-apiserver
#檢查監聽端口
$ netstat -ntlp|grep kube-apiserver
4. 部署keepalived - apiserver高可用(master節點)
4.1 安裝keepalived
# 在兩個主節點上安裝keepalived(一主一備),我這里選擇 k8s-m01, k8s-m02
$ yum install -y keepalived
4.2 創建keepalived配置文件
# 創建目錄
$ ssh <user>@<master-ip> "mkdir -p /etc/keepalived"
$ ssh <user>@<backup-ip> "mkdir -p /etc/keepalived"
# 分發配置文件
$ scp target/configs/keepalived-master.conf <user>@<master-ip>:/etc/keepalived/keepalived.conf
$ scp target/configs/keepalived-backup.conf <user>@<backup-ip>:/etc/keepalived/keepalived.conf
# 分發監測腳本
$ scp target/configs/check-apiserver.sh <user>@<master-ip>:/etc/keepalived/
$ scp target/configs/check-apiserver.sh <user>@<backup-ip>:/etc/keepalived/
4.3 啟動keepalived
# 分別在master和backup上啟動服務
$ systemctl enable keepalived && service keepalived start
# 檢查狀態
$ service keepalived status
# 查看日志
$ journalctl -f -u keepalived
# 訪問測試
$ curl --insecure https://<master-vip>:6443/
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
5. 部署kubectl(任意節點),我選擇 k8s-m01
kubectl 是 kubernetes 集群的命令行管理工具,它默認從 ~/.kube/config 文件讀取 kube-apiserver 地址、證書、用戶名等信息。
5.1 創建 admin 證書和私鑰
kubectl 與 apiserver https 安全端口通信,apiserver 對提供的證書進行認證和授權。
kubectl 作為集群的管理工具,需要被授予最高權限。這里創建具有最高權限的 admin 證書。
$ cd target/pki/admin
$ cat admin-csr.json
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "seven"
}
]
}
- O 為
system:masters
,kube-apiserver 收到該證書后將請求的 Group 設置為 system:masters; - 預定義的 ClusterRoleBinding
cluster-admin
將 Groupsystem:masters
與 Rolecluster-admin
綁定,該 Role 授予所有 API的權限; - 該證書只會被 kubectl 當做 client 證書使用,所以 hosts 字段為空;
# 創建證書、私鑰
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
5.2 創建kubeconfig配置文件
kubeconfig 為 kubectl 的配置文件,包含訪問 apiserver 的所有信息,如 apiserver 地址、CA 證書和自身使用的證書
# 設置集群參數
$ kubectl config set-cluster kubernetes \
--certificate-authority=../ca.pem \
--embed-certs=true \
--server=https://<MASTER_VIP>:6443 \
--kubeconfig=kube.config
# 設置客戶端認證參數
$ kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem \
--embed-certs=true \
--kubeconfig=kube.config
# 設置上下文參數
$ kubectl config set-context admin@kubernetes \
--cluster=kubernetes \
--user=admin \
--kubeconfig=kube.config
# 設置默認上下文
$ kubectl config use-context admin@kubernetes --kubeconfig=kube.config
# 分發到目標節點
$ scp kube.config <user>@<node-ip>:~/.kube/config
--certificate-authority
:驗證 kube-apiserver 證書的根證書;--client-certificate
、--client-key
:剛生成的admin
證書和私鑰,連接 kube-apiserver 時使用;--embed-certs=true
:將 ca.pem 和 admin.pem 證書內容嵌入到生成的 kubectl.kubeconfig 文件中(不加時,寫入的是證書文件路徑,后續拷貝 kubeconfig 到其它機器時,還需要單獨拷貝證書文件,不方便。);
5.3 授予 kubernetes 證書訪問 kubelet API 的權限
在執行 kubectl exec、run、logs 等命令時,apiserver 會轉發到 kubelet。這里定義 RBAC 規則,授權 apiserver 調用 kubelet API。
$ kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes
5.4 小測試
# 查看集群信息
$ kubectl cluster-info
$ kubectl get all -A
$ kubectl get cs
6. 部署controller-manager(master節點)
controller-manager啟動后將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用后,剩余節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。
6.1 創建證書和私鑰
查看證書請求。
$ cd target/pki/controller-manager
$ cat controller-manager-csr.json
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"172.18.0.100",
"172.18.0.101",
"172.18.0.102"
],
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:kube-controller-manager",
"OU": "seven"
}
]
}
- hosts 列表包含所有 kube-controller-manager 節點 IP;
- CN 和 O 均為
system:kube-controller-manager
,kubernetes 內置的 ClusterRoleBindingssystem:kube-controller-manager
賦予 kube-controller-manager 工作所需的權限。
# 生成證書、私鑰
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes controller-manager-csr.json | cfssljson -bare controller-manager
# 分發到每個master節點
$ scp controller-manager*.pem <user>@<node-ip>:/etc/kubernetes/pki/
6.2 創建controller-manager的kubeconfig
# 創建kubeconfig
$ kubectl config set-cluster kubernetes \
--certificate-authority=../ca.pem \
--embed-certs=true \
--server=https://<MASTER_VIP>:6443 \
--kubeconfig=controller-manager.kubeconfig
$ kubectl config set-credentials system:kube-controller-manager \
--client-certificate=controller-manager.pem \
--client-key=controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=controller-manager.kubeconfig
$ kubectl config set-context system:kube-controller-manager@kubernetes \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=controller-manager.kubeconfig
$ kubectl config use-context system:kube-controller-manager@kubernetes --kubeconfig=controller-manager.kubeconfig
# 分發controller-manager.kubeconfig
$ scp controller-manager.kubeconfig <user>@<node-ip>:/etc/kubernetes/
6.3 創建service文件
# scp配置文件到每個master節點
$ scp target/<node-ip>/services/kube-controller-manager.service <user>@<node-ip>:/etc/systemd/system/
6.4 啟動服務
# 啟動服務
$ systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl restart kube-controller-manager
# 檢查狀態
$ service kube-controller-manager status
# 查看日志
$ journalctl -f -u kube-controller-manager
# 查看leader
$ kubectl get endpoints kube-controller-manager --namespace=kube-system -o yaml
7. 部署scheduler(master節點)
scheduler啟動后將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用后,剩余節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。
7.1 創建證書和私鑰
查看證書請求文件。
$ cd target/pki/scheduler
$ cat scheduler-csr.json
{
"CN": "system:kube-scheduler",
"hosts": [
"127.0.0.1",
"172.18.0.100",
"172.18.0.101",
"172.18.0.102"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:kube-scheduler",
"OU": "seven"
}
]
}
- hosts 列表包含所有 kube-scheduler 節點 IP;
- CN 和 O 均為
system:kube-scheduler
,kubernetes 內置的 ClusterRoleBindingssystem:kube-scheduler
將賦予 kube-scheduler 工作所需的權限;
# 生成證書、私鑰
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes scheduler-csr.json | cfssljson -bare kube-scheduler
# 分發到每個master節點
$ scp kube-scheduler*.pem <user>@<node-ip>:/etc/kubernetes/pki/
7.2 創建scheduler的kubeconfig
# 創建kubeconfig
$ kubectl config set-cluster kubernetes \
--certificate-authority=../ca.pem \
--embed-certs=true \
--server=https://<MASTER_VIP>:6443 \
--kubeconfig=kube-scheduler.kubeconfig
$ kubectl config set-credentials system:kube-scheduler \
--client-certificate=kube-scheduler.pem \
--client-key=kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=kube-scheduler.kubeconfig
$ kubectl config set-context system:kube-scheduler@kubernetes \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=kube-scheduler.kubeconfig
$ kubectl config use-context system:kube-scheduler@kubernetes --kubeconfig=kube-scheduler.kubeconfig
# 分發kubeconfig
$ scp kube-scheduler.kubeconfig <user>@<node-ip>:/etc/kubernetes/
7.3 創建service文件
# scp配置文件到每個master節點
$ scp target/<node-ip>/services/kube-scheduler.service <user>@<node-ip>:/etc/systemd/system/
$ scp target/<node-ip>/configs/kube-scheduler.config.yaml <user>@<node-ip>:/etc/kubernetes/
7.4 啟動服務
# 啟動服務
$ systemctl daemon-reload && systemctl enable kube-scheduler && systemctl restart kube-scheduler
# 檢查狀態
$ service kube-scheduler status
# 查看日志
$ journalctl -f -u kube-scheduler
# 查看leader
$ kubectl get endpoints kube-scheduler --namespace=kube-system -o yaml
8. 部署kubelet(worker節點)
8.1 創建bootstrap配置文件
# 創建 token
$ cd target/pki/admin
$ export BOOTSTRAP_TOKEN=$(kubeadm token create \
--description kubelet-bootstrap-token \
--groups system:bootstrappers:worker \
--kubeconfig kube.config)
# 設置集群參數
$ kubectl config set-cluster kubernetes \
--certificate-authority=../ca.pem \
--embed-certs=true \
--server=https://<MASTER_VIP>:6443 \
--kubeconfig=kubelet-bootstrap.kubeconfig
# 設置客戶端認證參數
$ kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=kubelet-bootstrap.kubeconfig
# 設置上下文參數
$ kubectl config set-context kubelet@kubernetes \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=kubelet-bootstrap.kubeconfig
# 設置默認上下文
$ kubectl config use-context kubelet@kubernetes --kubeconfig=kubelet-bootstrap.kubeconfig
# 把生成的配置copy到每個worker節點上
$ scp kubelet-bootstrap.kubeconfig <user>@<node-ip>:/etc/kubernetes/kubelet-bootstrap.kubeconfig
# 把ca分發到每個worker節點
$ scp target/pki/ca.pem <user>@<node-ip>:/etc/kubernetes/pki/
# 查看生成的 token
$ kubeadm token list --kubeconfig ~/.kube/config
- 向 kubeconfig 寫入的是 token,bootstrap 結束后 kube-controller-manager 為 kubelet 創建 client 和 server 證書;
- token 有效期為 1 天,超期后將不能再被用來 boostrap kubelet,且會被 kube-controller-manager 的 tokencleaner 清理;
- kube-apiserver 接收 kubelet 的 bootstrap token 后,將請求的 user 設置為
system:bootstrap:<Token ID>
,group 設置為system:bootstrappers
,后續將為這個 group 設置 ClusterRoleBinding;
8.2 kubelet配置文件
把kubelet配置文件分發到每個worker節點上
$ scp target/worker-<node-ip>/kubelet.config.json <user>@<node-ip>:/etc/kubernetes/
cat kubelet.config.json
{
"kind": "KubeletConfiguration",
"apiVersion": "kubelet.config.k8s.io/v1beta1",
"authentication": {
"x509": {
"clientCAFile": "/etc/kubernetes/pki/ca.pem"
},
"webhook": {
"enabled": true,
"cacheTTL": "2m0s"
},
"anonymous": {
"enabled": false
}
},
"authorization": {
"mode": "Webhook",
"webhook": {
"cacheAuthorizedTTL": "5m0s",
"cacheUnauthorizedTTL": "30s"
}
},
"address": "172.18.0.103",
"staticPodPath": "",
"port": 10250,
"readOnlyPort": 10255,
"cgroupDriver": "cgroupfs",
"hairpinMode": "promiscuous-bridge",
"serializeImagePulls": false,
"featureGates": {
"RotateKubeletClientCertificate": true,
"RotateKubeletServerCertificate": true
},
"clusterDomain": "cluster.local.",
"clusterDNS": ["10.96.0.2"]
}
- authentication.anonymous.enabled:設置為 false,不允許匿名訪問 10250 端口;
- authentication.x509.clientCAFile:指定簽名客戶端證書的 CA 證書,開啟 HTTPs 證書認證;
- authentication.webhook.enabled=true:開啟 HTTPs bearer token 認證;
同時配置了如下授權參數:
- authroization.mode=Webhook:開啟 RBAC 授權;
kubelet 收到請求后,使用 clientCAFile 對證書簽名進行認證,或者查詢 bearer token 是否有效。如果兩者都沒通過,則拒絕請求,提示 Unauthorized:
8.3 kubelet服務文件
把kubelet服務文件分發到每個worker節點上
$ scp target/worker-<node-ip>/kubelet.service <user>@<node-ip>:/etc/systemd/system/
8.4 啟動服務
kublet 啟動時查找配置的 --kubeletconfig 文件是否存在,如果不存在則使用 --bootstrap-kubeconfig 向 kube-apiserver 發送證書簽名請求 (CSR)。
kube-apiserver 收到 CSR 請求后,對其中的 Token 進行認證(事先使用 kubeadm 創建的 token),認證通過后將請求的 user 設置為 system:bootstrap:,group 設置為 system:bootstrappers,這就是Bootstrap Token Auth。
# bootstrap附權
$ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers
# 啟動服務
$ mkdir -p /var/lib/kubelet
$ mkdir -p /var/log/kubernetes
$ systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet
# 在master上Approve bootstrap請求
$ kubectl get csr
$ kubectl certificate approve <name>
# 查看服務狀態
$ service kubelet status
# 查看日志
$ journalctl -f -u kubelet
- kubelet 啟動后使用 --bootstrap-kubeconfig 向 kube-apiserver 發送 CSR 請求,當這個 CSR 被 approve 后,kube-controller-manager 為 kubelet 創建 TLS 客戶端證書、私鑰和 --kubeletconfig 文件。
- 注意:kube-controller-manager 需要配置 --cluster-signing-cert-file 和 --cluster-signing-key-file 參數,才會為 TLS Bootstrap 創建證書和私鑰。
9. 部署kube-proxy(worker節點)
9.1 創建證書和私鑰
查看證書請求文件。
$ cd target/pki/proxy
cat kube-proxy-csr.json
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "seven"
}
]
}
- CN:指定該證書的 User 為
system:kube-proxy
; - 預定義的 RoleBinding
system:node-proxier
將Usersystem:kube-proxy
與 Rolesystem:node-proxier
綁定,該 Role 授予了調用kube-apiserver
Proxy 相關 API 的權限; - 該證書只會被 kube-proxy 當做 client 證書使用,所以 hosts 字段為空;
$ cfssl gencert -ca=../ca.pem \
-ca-key=../ca-key.pem \
-config=../ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
9.2 創建和分發 kubeconfig 文件
# 創建kube-proxy.kubeconfig
$ kubectl config set-cluster kubernetes \
--certificate-authority=../ca.pem \
--embed-certs=true \
--server=https://<master-vip>:6443 \
--kubeconfig=kube-proxy.kubeconfig
$ kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
$ kubectl config set-context kube-proxy@kubernetes \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
$ kubectl config use-context kube-proxy@kubernetes --kubeconfig=kube-proxy.kubeconfig
# 分發kube-proxy.kubeconfig 到 node 節點
$ scp kube-proxy.kubeconfig <user>@<node-ip>:/etc/kubernetes/
9.3 分發kube-proxy.config
$ scp target/worker-<node-ip>/kube-proxy.config.yaml <user>@<node-ip>:/etc/kubernetes/
9.4 分發kube-proxy服務文件
$ scp target/services/kube-proxy.service <user>@<node-ip>:/etc/systemd/system/
9.5 啟動服務
# 創建依賴目錄
$ mkdir -p /var/lib/kube-proxy
# 啟動服務
$ systemctl daemon-reload && systemctl enable kube-proxy && systemctl restart kube-proxy
# 查看狀態
$ service kube-proxy status
# 查看日志
$ journalctl -f -u kube-proxy
目前是 iptables 模式,使用 ipvs 模式可以修改文件 kube-proxy.config.yaml
我這里遇到的一個問題是 iptables 版本過低,如果遇到,可以編譯安裝使用新版本。
10. 部署CNI插件 - calico
我們使用calico官方的安裝方式來部署。
# 創建目錄(在配置了kubectl的節點上執行)
$ mkdir -p /etc/kubernetes/addons
# 上傳calico配置到配置好kubectl的節點(一個節點即可)
$ scp target/addons/calico.yaml <user>@<node-ip>:/etc/kubernetes/addons/
# 部署calico
$ kubectl apply -f /etc/kubernetes/addons/calico.yaml
# 查看狀態
$ kubectl get pods -n kube-system
https://docs.projectcalico.org/v3.10/getting-started/kubernetes/
11. 部署DNS插件 - coredns
# 上傳配置文件
$ scp target/addons/coredns.yaml <user>@<node-ip>:/etc/kubernetes/addons/
# 部署coredns
$ kubectl apply -f /etc/kubernetes/addons/coredns.yaml
https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base
四、集群可用性測試
1. 創建nginx ds
# 寫入配置
$ cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-ds
labels:
app: nginx-ds
spec:
type: NodePort
selector:
app: nginx-ds
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
labels:
addonmanager.kubernetes.io/mode: Reconcile
spec:
template:
metadata:
labels:
app: nginx-ds
spec:
containers:
- name: my-nginx
image: nginx:1.7.9
ports:
- containerPort: 80
selector:
matchLabels:
app: nginx-ds
EOF
# 創建ds
$ kubectl apply -f nginx-ds.yml
2. 檢查各種ip連通性
# 檢查各 Node 上的 Pod IP 連通性(主節點沒有calico所以不能訪問podip)
$ kubectl get pods -o wide
# 在每個worker節點上ping pod ip
$ ping <pod-ip>
# 檢查service可達性
$ kubectl get svc
# 在每個worker節點上訪問服務(主節點沒有proxy所以不能訪問service-ip)
$ curl <service-ip>:<port>
# 在每個節點檢查node-port可用性
$ curl <node-ip>:<port>
3. 檢查dns可用性
# 創建一個nginx pod
$ cat > pod-nginx.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
EOF
# 創建pod
$ kubectl apply -f pod-nginx.yaml
# 進入pod,查看dns
$ kubectl exec nginx -it -- /bin/bash
# 查看dns配置
root@nginx:/# cat /etc/resolv.conf
# 查看名字是否可以正確解析
root@nginx:/# ping nginx-ds
root@nginx:/# ping kubernetes
五. 部署dashboard
1. 部署dashboard
# 上傳dashboard配置
$ scp target/addons/dashboard-all.yaml <user>@<node-ip>:/etc/kubernetes/addons/
# 創建服務
$ kubectl apply -f /etc/kubernetes/addons/dashboard-all.yaml
# 查看服務運行情況
$ kubectl get deployment kubernetes-dashboard -n kube-system
$ kubectl --namespace kube-system get pods -o wide
$ kubectl get services kubernetes-dashboard -n kube-system
$ netstat -ntlp|grep 8401
2. 訪問dashboard
為了集群安全,從 1.7 開始,dashboard 只允許通過 https訪問,我們使用nodeport的方式暴露服務,可以使用 https://NodeIP:NodePort 地址訪問。
關於自定義證書
默認dashboard的證書是自動生成的,肯定是非安全的證書,如果大家有域名和對應的安全證書可以自己替換掉。使用安全的域名方式訪問dashboard。
在dashboard-all.yaml中增加dashboard啟動參數,可以指定證書文件,其中證書文件是通過secret注進來的。
--tls-cert-file=dashboard.cer --tls-key-file=dashboard.key
3. 登錄dashboard
Dashboard 默認只支持 token 認證,所以如果使用 KubeConfig 文件,需要在該文件中指定 token,我們這里使用token的方式登錄
# 創建service account
$ kubectl create sa dashboard-admin -n kube-system
# 創建角色綁定關系
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 查看dashboard-admin的secret名字
$ ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')
# 打印secret的token
$ kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}'
六、部署 metrics-server
metrics-server 通過 kube-apiserver 發現所有節點,然后調用 kubelet APIs(通過 https 接口)獲得各節點(Node)和 Pod 的 CPU、Memory 等資源使用情況。
從 Kubernetes 1.12 開始,kubernetes 的安裝腳本移除了 Heapster,從 1.13 開始完全移除了對 Heapster 的支持,Heapster 不再被維護。
1. 安裝 metrics-server
$ cd target/addons
$ git clone https://github.com/kubernetes-incubator/metrics-server.git
$ cd metrics-server/deploy/1.8+/
修改metrics-server-deployment.yaml
文件,把 metrics-server 修改為如下命令行參數:
containers:
- name: metrics-server
image: wangzan18/metrics-server-amd64:v0.3.6
args:
- --cert-dir=/tmp
- --secure-port=4443
- --metric-resolution=30s
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
- --metric-resolution=30s:從 kubelet 采集數據的周期;
- --kubelet-preferred-address-types:優先使用 InternalIP 來訪問 kubelet,這樣可以避免節點名稱沒有 DNS 解析記錄時,通過節點名稱調用節點 kubelet API 失敗的情況(未配置時默認的情況);
2. 部署
$ cd target/addons/metrics-server/deploy/1.8+/
$ kubectl apply -f .