實驗環境:
k8s集群master01:192.168.1.11
k8s集群master02:192.168.1.22
master虛擬ip:192.168.1.100
k8s集群node01:192.168.1.33
k8s集群node01:192.168.1.44
nginx+keepalive01(master):192.168.1.55
nginx+keepalive02(backup):192.168.1.66
在所有機器上初始化系統:
systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X#關閉selinux
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config#關閉swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab #分別設置主機名
hostnamectl set-hostname master01
hostnamectl set-hostname master02
hostnamectl set-hostname node01
hostnamectl set-hostname node02#添加hosts文件
cat >> /etc/hosts << EOF
192.168.1.11 master01
192.168.1.22 master02
192.168.1.33 node01
192.168.1.44 node02
EOF#調整內核參數
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF
#開啟網橋模式,可將網橋的流量傳遞給iptables鏈
#關閉ipv6協議
sysctl --system#時間同步
yum install ntpdate -y
ntpdate time.windows.com
在所有node節點部署docker:
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker.service
systemctl enable docker.service
部署etcd集群:
準備cfssl證書生成工具cfssl、cfssljson、cfssl-certinfo放在master01上的/usr/local/bin/下并賦予執行權限
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
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo
chmod +x /usr/local/bin/cfssl*
創建/opt/k8s/目錄并使用腳本生成CA證書、etcd服務器證書以及私鑰
mkdir /opt/k8s
cd /opt/k8s/
chmod +x etcd-cert.sh etcd.sh
mkdir /opt/k8s/etcd-cert
mv etcd-cert.sh etcd-cert/
cd /opt/k8s/etcd-cert/
./etcd-cert.sh
etcd-cert.sh腳本:
#!/bin/bash# 配置證書生成策略
cat > ca-config.json <<EOF
{"signing": {"default": {"expiry": "87600h"},"profiles": {"www": {"expiry": "87600h","usages": ["signing","key encipherment","server auth","client auth"]}}}
}
EOF# 生成根證書的請求文件
cat > ca-csr.json <<EOF
{"CN": "etcd","key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "Beijing","ST": "Beijing"}]
}
EOF# 使用 CSR 文件生成根證書和私鑰
cfssl gencert -initca ca-csr.json | cfssljson -bare ca# 生成服務器證書的請求文件
cat > server-csr.json <<EOF
{"CN": "etcd","hosts": ["192.168.1.11","192.168.1.33","192.168.1.44"],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing","ST": "BeiJing"}]
}
EOF# 使用根證書簽發服務器證書和私鑰
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
上傳etcd-v3.4.9-linux-amd64.tar.gz 到/opt/k8s/后啟動etcd服務
cd /opt/k8s/
tar zxvf etcd-v3.4.9-linux-amd64.tar.gz
mkdir -p /opt/etcd/{cfg,bin,ssl}
cd /opt/k8s/etcd-v3.4.9-linux-amd64/
mv etcd etcdctl /opt/etcd/bin/
cp /opt/k8s/etcd-cert/*.pem /opt/etcd/ssl/
cd /opt/k8s/
./etcd.sh etcd01 192.168.1.11 etcd02=https://192.168.1.33:2380,etcd03=https://192.168.1.44:2380
把etcd相關證書文件、命令文件和服務管理文件全部拷貝到另外兩個etcd集群節點
scp -r /opt/etcd/ root@192.168.1.33:/opt/
scp -r /opt/etcd/ root@192.168.1.44:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.33:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.44:/usr/lib/systemd/system/
在node節點分別修改etcd配置文件并啟動etcd
vim /opt/etcd/cfg/etcd
systemctl start etcd
systemctl enable etcd
systemctl status etcd
檢查etcd集群狀態
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" endpoint health --write-out=table
這個命令用于檢查 etcd 集群中各個節點的健康狀態,并以表格形式輸出。
ETCDCTL_API=3
:設置 etcdctl 的 API 版本為 3。/opt/etcd/bin/etcdctl
:指定 etcdctl 的路徑。--cacert=/opt/etcd/ssl/ca.pem
:指定根證書文件的路徑,用于驗證 etcd 服務器證書的有效性。--cert=/opt/etcd/ssl/server.pem
:指定客戶端證書的路徑,用于與 etcd 服務器進行雙向身份驗證。--key=/opt/etcd/ssl/server-key.pem
:指定客戶端私鑰的路徑,用于與 etcd 服務器進行雙向身份驗證。--endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379"
:指定 etcd 集群的各個節點的地址和端口。endpoint health
:檢查 etcd 集群中各個節點的健康狀態。--write-out=table
:以表格形式輸出結果。
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" endpoint status --write-out=table
這個命令用于獲取 etcd 集群中各個節點的狀態,并以表格形式輸出。
ETCDCTL_API=3
:設置 etcdctl 的 API 版本為 3。/opt/etcd/bin/etcdctl
:指定 etcdctl 的路徑。--cacert=/opt/etcd/ssl/ca.pem
:指定根證書文件的路徑,用于驗證 etcd 服務器證書的有效性。--cert=/opt/etcd/ssl/server.pem
:指定客戶端證書的路徑,用于與 etcd 服務器進行雙向身份驗證。--key=/opt/etcd/ssl/server-key.pem
:指定客戶端私鑰的路徑,用于與 etcd 服務器進行雙向身份驗證。--endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379"
:指定 etcd 集群的各個節點的地址和端口。endpoint status
:獲取 etcd 集群中各個節點的狀態。--write-out=table
:以表格形式輸出結果。
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" --write-out=table member list
這個命令用于列出 etcd 集群中的成員,并以表格形式輸出。
ETCDCTL_API=3
:設置 etcdctl 的 API 版本為 3。/opt/etcd/bin/etcdctl
:指定 etcdctl 的路徑。--cacert=/opt/etcd/ssl/ca.pem
:指定根證書文件的路徑,用于驗證 etcd 服務器證書的有效性。--cert=/opt/etcd/ssl/server.pem
:指定客戶端證書的路徑,用于與 etcd 服務器進行雙向身份驗證。--key=/opt/etcd/ssl/server-key.pem
:指定客戶端私鑰的路徑,用于與 etcd 服務器進行雙向身份驗證。--endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379"
:指定 etcd 集群的各個節點的地址和端口。member list
:列出 etcd 集群中的成員。--write-out=table
:以表格形式輸出結果。
部署master:
在/opt/k8s/目錄中準備admin.sh、apiserver.sh、controller-manager.sh、scheduler.sh、k8s-sert.sh,kubernetes-server-linux-amd64.tar.gz
admin.sh
#!/bin/bash
mkdir /root/.kube
KUBE_CONFIG="/root/.kube/config"
KUBE_APISERVER="https://192.168.1.11:6443"cd /opt/k8s/k8s-cert/kubectl config set-cluster kubernetes \--certificate-authority=/opt/kubernetes/ssl/ca.pem \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials cluster-admin \--client-certificate=./admin.pem \--client-key=./admin-key.pem \--embed-certs=true \--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \--cluster=kubernetes \--user=cluster-admin \--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
apiserver.sh
#!/bin/bash
#example: apiserver.sh your_master_ip https://your_etcd01_ip:2379,https://your_etcd02_ip:2379,https://your_etcd03_ip:2379
#創建 kube-apiserver 啟動參數配置文件
MASTER_ADDRESS=$1
ETCD_SERVERS=$2cat >/opt/kubernetes/cfg/kube-apiserver <<EOF
KUBE_APISERVER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcd-servers=${ETCD_SERVERS} \\
--bind-address=${MASTER_ADDRESS} \\
--secure-port=6443 \\
--advertise-address=${MASTER_ADDRESS} \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-50000 \\
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem \\
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--service-account-issuer=api \\
--service-account-signing-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--etcd-cafile=/opt/etcd/ssl/ca.pem \\
--etcd-certfile=/opt/etcd/ssl/server.pem \\
--etcd-keyfile=/opt/etcd/ssl/server-key.pem \\
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--proxy-client-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--proxy-client-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--requestheader-allowed-names=kubernetes \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
EOF#--logtostderr=true:啟用日志。輸出日志到標準錯誤控制臺,不輸出到文件
#--v=4:日志等級。指定輸出日志的級別,v=4為調試級別詳細輸出
#--etcd-servers:etcd集群地址。指定etcd服務器列表(格式://ip:port),逗號分隔
#--bind-address:監聽地址。指定 HTTPS 安全接口的監聽地址,默認值0.0.0.0
#--secure-port:https安全端口。指定 HTTPS 安全接口的監聽端口,默認值6443
#--advertise-address:集群通告地址。通過該 ip 地址向集群其他節點公布 api server 的信息,必須能夠被其他節點訪問
#--allow-privileged=true:啟用授權。允許擁有系統特權的容器運行,默認值false
#--service-cluster-ip-range:Service虛擬IP地址段。指定 Service Cluster IP 地址段
#--enable-admission-plugins:準入控制模塊。kuberneres集群的準入控制機制,各控制模塊以插件的形式依次生效,集群時必須包含ServiceAccount,運行在認證(Authentication)、授權(Authorization)之后,Admission Control是權限認證鏈上的最后一環, 對請求API資源對象進行修改和校驗
#--authorization-mode:認證授權,啟用RBAC授權和節點自管理。在安全端口使用RBAC,Node授權模式,未通過授權的請求拒絕,默認值AlwaysAllow。RBAC是用戶通過角色與權限進行關聯的模式;Node模式(節點授權)是一種特殊用途的授權模式,專門授權由kubelet發出的API請求,在進行認證時,先通過用戶名、用戶分組驗證是否是集群中的Node節點,只有是Node節點的請求才能使用Node模式授權
#--enable-bootstrap-token-auth:啟用TLS bootstrap機制。在apiserver上啟用Bootstrap Token 認證
#--token-auth-file=/opt/kubernetes/cfg/token.csv:指定bootstrap token認證文件路徑
#--service-node-port-range:指定 Service NodePort 的端口范圍,默認值30000-32767
#–-kubelet-client-xxx:apiserver訪問kubelet客戶端證書
#--tls-xxx-file:apiserver https證書
#1.20版本必須加的參數:–-service-account-issuer,–-service-account-signing-key-file
#--etcd-xxxfile:連接Etcd集群證書
#–-audit-log-xxx:審計日志
#啟動聚合層相關配置:–requestheader-client-ca-file,–proxy-client-cert-file,–proxy-client-key-file,–requestheader-allowed-names,–requestheader-extra-headers-prefix,–requestheader-group-headers,–requestheader-username-headers,–enable-aggregator-routing#創建 kube-apiserver.service 服務管理文件
cat >/usr/lib/systemd/system/kube-apiserver.service <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-apiserver
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure[Install]
WantedBy=multi-user.target
EOFsystemctl daemon-reload
systemctl enable kube-apiserver
systemctl restart kube-apiserver
controller-manager.sh
#!/bin/bash
##創建 kube-controller-manager 啟動參數配置文件
MASTER_ADDRESS=$1cat >/opt/kubernetes/cfg/kube-controller-manager <<EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-controller-manager.kubeconfig \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--cluster-signing-duration=87600h0m0s"
EOF#––leader-elect:當該組件啟動多個時,自動選舉(HA)
#-–kubeconfig:連接 apiserver 用的配置文件,用于識別 k8s 集群
#--cluster-cidr=10.244.0.0/16:pod資源的網段,需與pod網絡插件的值設置一致。通常,Flannel網絡插件的默認為10.244.0.0/16,Calico插件的默認值為192.168.0.0/16
#--cluster-signing-cert-file/–-cluster-signing-key-file:自動為kubelet頒發證書的CA,與apiserver保持一致。指定簽名的CA機構根證書,用來簽名為 TLS BootStrapping 創建的證書和私鑰
#--root-ca-file:指定根CA證書文件路徑,用來對 kube-apiserver 證書進行校驗,指定該參數后,才會在 Pod 容器的 ServiceAccount 中放置該 CA 證書文件
#--experimental-cluster-signing-duration:設置為 TLS BootStrapping 簽署的證書有效時間為10年,默認為1年##生成kube-controller-manager證書
cd /opt/k8s/k8s-cert/
#創建證書請求文件
cat > kube-controller-manager-csr.json << EOF
{"CN": "system:kube-controller-manager","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing", "ST": "BeiJing","O": "system:masters","OU": "System"}]
}
EOF#生成證書
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-controller-manager.kubeconfig"
KUBE_APISERVER="https://192.168.1.11:6443"kubectl config set-cluster kubernetes \--certificate-authority=/opt/kubernetes/ssl/ca.pem \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-controller-manager \--client-certificate=./kube-controller-manager.pem \--client-key=./kube-controller-manager-key.pem \--embed-certs=true \--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \--cluster=kubernetes \--user=kube-controller-manager \--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}##創建 kube-controller-manager.service 服務管理文件
cat >/usr/lib/systemd/system/kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-controller-manager
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure[Install]
WantedBy=multi-user.target
EOFsystemctl daemon-reload
systemctl enable kube-controller-manager
systemctl restart kube-controller-manager
scheduler.sh
#!/bin/bash
##創建 kube-scheduler 啟動參數配置文件
MASTER_ADDRESS=$1cat >/opt/kubernetes/cfg/kube-scheduler <<EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-scheduler.kubeconfig \\
--bind-address=127.0.0.1"
EOF#-–kubeconfig:連接 apiserver 用的配置文件,用于識別 k8s 集群
#--leader-elect=true:當該組件啟動多個時,自動啟動 leader 選舉
#k8s中Controller-Manager和Scheduler的選主邏輯:k8s中的etcd是整個集群所有狀態信息的存儲,涉及數據的讀寫和多個etcd之間數據的同步,對數據的一致性要求嚴格,所以使用較復雜的 raft 算法來選擇用于提交數據的主節點。而 apiserver 作為集群入口,本身是無狀態的web服務器,多個 apiserver 服務之間直接負載請求并不需要做選主。Controller-Manager 和 Scheduler 作為任務類型的組件,比如 controller-manager 內置的 k8s 各種資源對象的控制器實時的 watch apiserver 獲取對象最新的變化事件做期望狀態和實際狀態調整,調度器watch未綁定節點的pod做節點選擇,顯然多個這些任務同時工作是完全沒有必要的,所以 controller-manager 和 scheduler 也是需要選主的,但是選主邏輯和 etcd 不一樣的,這里只需要保證從多個 controller-manager 和 scheduler 之間選出一個 leader 進入工作狀態即可,而無需考慮它們之間的數據一致和同步。##生成kube-scheduler證書
cd /opt/k8s/k8s-cert/
#創建證書請求文件
cat > kube-scheduler-csr.json << EOF
{"CN": "system:kube-scheduler","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing","ST": "BeiJing","O": "system:masters","OU": "System"}]
}
EOF#生成證書
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-scheduler.kubeconfig"
KUBE_APISERVER="https://192.168.1.11:6443"kubectl config set-cluster kubernetes \--certificate-authority=/opt/kubernetes/ssl/ca.pem \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-scheduler \--client-certificate=./kube-scheduler.pem \--client-key=./kube-scheduler-key.pem \--embed-certs=true \--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \--cluster=kubernetes \--user=kube-scheduler \--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}##創建 kube-scheduler.service 服務管理文件
cat >/usr/lib/systemd/system/kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-scheduler
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure[Install]
WantedBy=multi-user.target
EOFsystemctl daemon-reload
systemctl enable kube-scheduler
systemctl restart kube-scheduler
k8s-sert.sh
#!/bin/bash
cat > ca-config.json <<EOF
{"signing": {"default": {"expiry": "87600h"},"profiles": {"kubernetes": {"expiry": "87600h","usages": ["signing","key encipherment","server auth","client auth"]}}}
}
EOF#生成CA證書和私鑰(根證書和私鑰)
cat > ca-csr.json <<EOF
{"CN": "kubernetes","key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "Beijing","ST": "Beijing","O": "k8s","OU": "System"}]
}
EOFcfssl gencert -initca ca-csr.json | cfssljson -bare ca -#-----------------------
#生成 apiserver 的證書和私鑰(apiserver和其它k8s組件通信使用)
#hosts中將所有可能作為 apiserver 的 ip 添加進去,后面 keepalived 使用的 VIP 也要加入
cat > apiserver-csr.json <<EOF
{"CN": "kubernetes","hosts": ["10.0.0.1","127.0.0.1","192.168.1.11","192.168.1.22","192.168.1.100","192.168.1.55","192.168.1.66","kubernetes","kubernetes.default","kubernetes.default.svc","kubernetes.default.svc.cluster","kubernetes.default.svc.cluster.local"],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing","ST": "BeiJing","O": "k8s","OU": "System"}]
}
EOFcfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes apiserver-csr.json | cfssljson -bare apiserver#-----------------------
#生成 kubectl 連接集群的證書和私鑰,具有admin權限
cat > admin-csr.json <<EOF
{"CN": "admin","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing","ST": "BeiJing","O": "system:masters","OU": "System"}]
}
EOFcfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin#-----------------------
#生成 kube-proxy 的證書和私鑰
cat > kube-proxy-csr.json <<EOF
{"CN": "system:kube-proxy","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","L": "BeiJing","ST": "BeiJing","O": "k8s","OU": "System"}]
}
EOFcfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
chmod +x *.sh
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
mkdir /opt/k8s/k8s-cert
mv /opt/k8s/k8s-cert.sh /opt/k8s/k8s-cert
cd /opt/k8s/k8s-cert/
./k8s-cert.sh
cp ca*pem apiserver*pem /opt/kubernetes/ssl/
cd /opt/k8s/
tar zxvf kubernetes-server-linux-amd64.tar.gz
cd /opt/k8s/kubernetes/server/bin
cp kube-apiserver kubectl kube-controller-manager kube-scheduler /opt/kubernetes/bin/
ln -s /opt/kubernetes/bin/* /usr/local/bin/
cd /opt/k8s/
vim token.sh
#!/bin/bash
#獲取隨機數前16個字節內容,以十六進制格式輸出,并刪除其中空格
BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
#生成 token.csv 文件,按照 Token序列號,用戶名,UID,用戶組 的格式生成
cat > /opt/kubernetes/cfg/token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
chmod +x token.sh
./token.sh
cat /opt/kubernetes/cfg/token.csv
cd /opt/k8s/
./apiserver.sh 192.168.1.11 https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379
ps aux | grep kube-apiserver
netstat -natp | grep 6443
cd /opt/k8s/
#啟動 scheduler 服務
./scheduler.sh
ps aux | grep kube-scheduler
#啟動 controller-manager 服務
./controller-manager.sh
ps aux | grep kube-controller-manager
#生成kubectl連接集群的kubeconfig文件
./admin.sh
#通過kubectl工具查看當前集群組件狀態
kubectl get cs
部署node:
在所有node操作
創建kubernetes工作目錄
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
準備kubelet.sh、proxy.sh
kubelet.sh
#!/bin/bashNODE_ADDRESS=$1
DNS_SERVER_IP=${2:-"10.0.0.2"}#創建 kubelet 啟動參數配置文件
cat >/opt/kubernetes/cfg/kubelet <<EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=${NODE_ADDRESS} \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet.config \\
--cert-dir=/opt/kubernetes/ssl \\
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
EOF#--hostname-override:指定kubelet節點在集群中顯示的主機名或IP地址,默認使用主機hostname;kube-proxy和kubelet的此項參數設置必須完全一致
#--network-plugin:啟用CNI
#--kubeconfig:指定kubelet.kubeconfig文件位置,當前為空路徑,會自動生成,用于如何連接到apiserver,里面含有kubelet證書,master授權完成后會在node節點上生成 kubelet.kubeconfig 文件
#--bootstrap-kubeconfig:指定連接 apiserver 的 bootstrap.kubeconfig 文件
#--config:指定kubelet配置文件的路徑,啟動kubelet時將從此文件加載其配置
#--cert-dir:指定master頒發的kubelet證書生成目錄
#--pod-infra-container-image:指定Pod基礎容器(Pause容器)的鏡像。Pod啟動的時候都會啟動一個這樣的容器,每個pod之間相互通信需要Pause的支持,啟動Pause需要Pause基礎鏡像#----------------------
#創建kubelet配置文件(該文件實際上就是一個yml文件,語法非常嚴格,不能出現tab鍵,冒號后面必須要有空格,每行結尾也不能有空格)
cat >/opt/kubernetes/cfg/kubelet.config <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: ${NODE_ADDRESS}
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS:
- ${DNS_SERVER_IP}
clusterDomain: cluster.local
failSwapOn: false
authentication:anonymous:enabled: true
EOF#PS:當命令行參數與此配置文件(kubelet.config)有相同的值時,就會覆蓋配置文件中的該值。#----------------------
#創建 kubelet.service 服務管理文件
cat >/usr/lib/systemd/system/kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
KillMode=process[Install]
WantedBy=multi-user.target
EOFsystemctl daemon-reload
systemctl enable kubelet
systemctl restart kubelet
proxy.sh
#!/bin/bashNODE_ADDRESS=$1#創建 kube-proxy 啟動參數配置文件
cat >/opt/kubernetes/cfg/kube-proxy <<EOF
KUBE_PROXY_OPTS="--logtostderr=true \\
--v=4 \\
--hostname-override=${NODE_ADDRESS} \\
--cluster-cidr=172.17.0.0/16 \\
--proxy-mode=ipvs \\
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
EOF#--hostnameOverride: 參數值必須與 kubelet 的值一致,否則 kube-proxy 啟動后會找不到該 Node,從而不會創建任何 ipvs 規則
#--cluster-cidr:指定 Pod 網絡使用的聚合網段,Pod 使用的網段和 apiserver 中指定的 service 的 cluster ip 網段不是同一個網段。 kube-proxy 根據 --cluster-cidr 判斷集群內部和外部流量,指定 --cluster-cidr 選項后 kube-proxy 才會對訪問 Service IP 的請求做 SNAT,即來自非 Pod 網絡的流量被當成外部流量,訪問 Service 時需要做 SNAT。
#--proxy-mode:指定流量調度模式為ipvs模式,可添加--ipvs-scheduler選項指定ipvs調度算法(rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq)
#--kubeconfig: 指定連接 apiserver 的 kubeconfig 文件 #----------------------
#創建 kube-proxy.service 服務管理文件
cat >/usr/lib/systemd/system/kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Proxy
After=network.target[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-proxy
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure[Install]
WantedBy=multi-user.target
EOFsystemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy
chmod +x kubelet.sh proxy.sh
在 master01 節點上操作
cd /opt/k8s/kubernetes/server/bin
scp kubelet kube-proxy root@192.168.1.33:/opt/kubernetes/bin/
scp kubelet kube-proxy root@192.168.1.44:/opt/kubernetes/bin/
mkdir /opt/k8s/kubeconfig
cd /opt/k8s/kubeconfig
在/opt/k8s/kubeconfig/目錄下準備kubeconfig.sh
kubeconfig.sh
#!/bin/bash
#example: kubeconfig 192.168.1.11 /opt/k8s/k8s-cert/
#創建bootstrap.kubeconfig文件
#該文件中內置了 token.csv 中用戶的 Token,以及 apiserver CA 證書;kubelet 首次啟動會加載此文件,使用 apiserver CA 證書建立與 apiserver 的 TLS 通訊,使用其中的用戶 Token 作為身份標識向 apiserver 發起 CSR 請求BOOTSTRAP_TOKEN=$(awk -F ',' '{print $1}' /opt/kubernetes/cfg/token.csv)
APISERVER=$1
SSL_DIR=$2export KUBE_APISERVER="https://$APISERVER:6443"# 設置集群參數
kubectl config set-cluster kubernetes \--certificate-authority=$SSL_DIR/ca.pem \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=bootstrap.kubeconfig
#--embed-certs=true:表示將ca.pem證書寫入到生成的bootstrap.kubeconfig文件中# 設置客戶端認證參數,kubelet 使用 bootstrap token 認證
kubectl config set-credentials kubelet-bootstrap \--token=${BOOTSTRAP_TOKEN} \--kubeconfig=bootstrap.kubeconfig# 設置上下文參數
kubectl config set-context default \--cluster=kubernetes \--user=kubelet-bootstrap \--kubeconfig=bootstrap.kubeconfig# 使用上下文參數生成 bootstrap.kubeconfig 文件
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig#----------------------#創建kube-proxy.kubeconfig文件
# 設置集群參數
kubectl config set-cluster kubernetes \--certificate-authority=$SSL_DIR/ca.pem \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=kube-proxy.kubeconfig# 設置客戶端認證參數,kube-proxy 使用 TLS 證書認證
kubectl config set-credentials kube-proxy \--client-certificate=$SSL_DIR/kube-proxy.pem \--client-key=$SSL_DIR/kube-proxy-key.pem \--embed-certs=true \--kubeconfig=kube-proxy.kubeconfig# 設置上下文參數
kubectl config set-context default \--cluster=kubernetes \--user=kube-proxy \--kubeconfig=kube-proxy.kubeconfig# 使用上下文參數生成 kube-proxy.kubeconfig 文件
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
chmod +x kubeconfig.sh
./kubeconfig.sh 192.168.1.11 /opt/k8s/k8s-cert/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.1.33:/opt/kubernetes/cfg/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.1.44:/opt/kubernetes/cfg/
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap若執行失敗,可先給kubectl綁定默認cluster-admin管理員集群角色,授權集群操作權限
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous
在node01節點操作
cd /opt/
./kubelet.sh 192.168.1.33
ps aux | grep kubelet
在 master01 節點上操作
kubectl get csr
kubectl certificate approve node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFEkubectl get csr
在 node01 節點上操作
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
cd /opt/
./proxy.sh 192.168.1.33
ps aux | grep kube-proxy
部署 Calico網絡:
在 master01 節點上操作
準備calico.yaml 文件到 /opt/k8s 目錄中
# - name: CALICO_IPV4POOL_CIDR# value: "10.244.0.0/16"
修改里面定義 Pod 的網絡(CALICO_IPV4POOL_CIDR),需與前面 kube-controller-manager 配置文件指定的 cluster-cidr 網段一樣
kubectl apply -f calico.yaml
kubectl get pods -n kube-system
kubectl get nodes
部署node02:
在node01操作
cd /opt/
scp kubelet.sh proxy.sh root@192.168.1.44:/opt/
scp -r /opt/cni root@192.168.1.44:/opt/
在node02操作
cd /opt/
chmod +x kubelet.sh
./kubelet.sh 192.168.1.44
在 master01 節點上操作
kubectl get csr
kubectl certificate approve node-csr-nh4DGjA-xNcE_dJ0blI6HTgz-XcqTkD5MFiGQQ9mEoQ
kubectl get csr
在 node02 節點上操作
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
cd /opt/
chmod +x proxy.sh
./proxy.sh 192.168.1.44
在 master01 節點上操作
kubectl get nodes
部署 CoreDNS
在所有 node 節點上操作
上傳 coredns.tar 到 /opt 目錄中
cd /opt
docker load -i coredns.tar
在 master01 節點上操作
上傳 coredns.yaml 文件到 /opt/k8s 目錄中,部署 CoreDNS?
cd /opt/k8s
kubectl apply -f coredns.yaml
kubectl get pods -n kube-system
DNS 解析測試
kubectl run -it --rm dns-test --image=busybox:1.28.4 sh
如果出現以下報錯
[root@master01 k8s]# kubectl run -it ?--image=busybox:1.28.4 sh
If you don't see a command prompt, try pressing enter.
Error attaching, falling back to logs: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) ( pods/log sh)
需要添加 rbac的權限 ?直接使用kubectl綁定 ?clusteradmin 管理員集群角色 ?授權操作權限
[root@master01 k8s]# kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/cluster-system-anonymous created
master02 節點部署 :
從 master01 節點上拷貝證書文件、各master組件的配置文件和服務管理文件到 master02 節點
scp -r /opt/etcd/ root@192.168.1.22:/opt/
scp -r /opt/kubernetes/ root@192.168.1.22:/opt
scp -r /root/.kube root@192.168.1.22:/root
scp /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service root@192.168.1.22:/usr/lib/systemd/system/
在master02上修改配置文件kube-apiserver中的IP
vim /opt/kubernetes/cfg/kube-apiserver
--etcd-servers=https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379 \
--bind-address=192.168.1.22 \
--secure-port=6443 \
--advertise-address=192.168.1.22 \
--allow-privileged=true \
在 master02 節點上啟動各服務并設置開機自啟
systemctl start kube-apiserver.service
systemctl enable kube-apiserver.service
systemctl start kube-controller-manager.service
systemctl enable kube-controller-manager.service
systemctl start kube-scheduler.service
systemctl enable kube-scheduler.service
查看node節點狀態
ln -s /opt/kubernetes/bin/* /usr/local/bin/
kubectl get nodes