一、部署Kubernetes集群
1.1 Kubernetes介紹
Kubernetes(K8S)是Google開源的容器集群管理系統,K8S在Docker容器技術的基礎之上,大大地提高了容器化部署應用簡單高效。並且具備了完整的集群管理能力,涵蓋項目周期的各個環節。
Docker與Kubernetes聯系:Docker是一個容器引擎,用於運行容器,Kubernetes是一個容器編排系統,不具備容器引擎功能,相比Docker是一個更高級封裝,而他們在一起堪稱珠聯璧合。
1.2 創建Kubernetes集群方式
三種部署集群方式:
1、Minikube是一個工具,可以在本地快速運行一個單點的Kubernetes,嘗試Kubernetes或日常開發的用戶使用。不能用於生產環境。
2、Kubeadm也是一個工具,提供kubeadm init和kubeadm join,用於快速部署Kubernetes集群。Kubeadm降低部署門檻,但屏蔽了很多細節,遇到問題很難排查。
3、二進制包,從官方下載發行版的二進制包,手動部署每個組件,組成Kubernetes集群。我們這里使用二進制包部署Kubernetes集群,雖然手動部署麻煩點,但學習很多工作原理,更有利於后期維護。
1.3 集群部署架構規划
1.3.1 軟件環境
CentOS:AWS
Docker:18.9.5-ce
Kubernetes:1.14.1
Etcd:3.3.12
Calico:3.6.1
1.3.2 服務器角色
角色 |
IP |
組件 |
k8s-master1 |
172.31.50.170 |
kube-apiserver,kube-controller-manager,kube-scheduler,etcd,haproxy,keeplive |
k8s-master2 |
172.31.50.101 |
kube-apiserver,kube-controller-manager,kube-scheduler,etcd,haproxy,keeplive |
k8s-master3 |
172.31.58.221 |
kube-apiserver,kube-controller-manager,kube-scheduler,etcd,haproxy,keeplive |
k8s-node1 |
172.31.55.50 |
kubelet,kube-proxy,docker,calico |
k8s-node2 |
172.31.55.0 |
kubelet,kube-proxy,docker,calico |
|
192.168.10.24 |
masterHA集群的vip |
1.3.3 拓撲圖
如果不是雲環境,可以采用主流的軟件負載均衡器,例如LVS、HAProxy、Nginx。這里使用HAProxy作為apiserver負載均衡器,架構圖如下:
1.3.4 配置防火牆
1、關閉firewall
systemctl stop firewalld.service && systemctl disable firewalld.service
2、安裝iptables防火牆
yum install -y iptables-services
#master節點默認該防火牆配置文件
cat /etc/sysconfig/iptables
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT
#node節點清空該配置,后續也不要手動添加規則
echo "" >/etc/sysconfig/iptables
3、重啟防火牆
systemctl restart iptables.service && systemctl enable iptables.service
#說明:后續要添加端口,先重啟服務器再保存。
service iptables restart && service iptables save
4、關閉selinux
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config
cat /etc/selinux/config
注意:不要替換/etc/sysconfig/selinux文件,這是一個軟連接,不會生效。
1.3.5 設置主機名
#對每一個節點進行設置主機名
vim /etc/hostname
k8smaster1
注意:aws修改centos主機名需要通過下面命令
hostnamectl set-hostname --static k8smaster
vim /etc/cloud/cloud.cfg #最后一行添加
preserve_hostname: true
#重啟機器
reboot
#對每個節點配置IP和域名映射關系
vim /etc/hosts
172.31.50.170 k8smaster1 172.31.50.101 k8smaster2 172.31.58.221 k8smaster3 172.31.55.50 k8snode1 172.31.55.0 k8snode2
1.3.6 同步時間
yum install -y ntp
systemctl enable ntpd
systemctl start ntpd
timedatectl set-timezone Asia/Shanghai
timedatectl set-ntp yes
ntpq -p
1.4 部署etcd集群
在K8s-master1、K8s-master2、K8s-master3三個節點上部署etcd節點,並組成集群。
1.4.1 生成證書
在任意某一個etcd節點上安裝即可,主要使用生成的證書,其他節點復制過去即可。使用cfssl來生成自簽證書。
1、先下載cfssl工具
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
mv cfssl_linux-amd64 /usr/bin/cfssl
mv cfssljson_linux-amd64 /usr/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
2、創建三個文件
makdir etcd_ca
cd etcd_ca
# 創建 Etcd根證書配置文件
cat > ca-config.json <<EOF { "signing": { "default": { "expiry": "87600h" }, "profiles": { "www": { "expiry": "87600h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } } EOF
# 創建 Etcd根證書請求文件
cat > ca-csr.json <<EOF { "CN": "etcd CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "ST": "Beijing" } ] } EOF
# 創建 Etcd服務證書請求文件
cat > server-csr.json <<EOF { "CN": "etcd", "hosts": [ "172.31.50.170", "172.31.50.101", "172.31.58.221" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "BeiJing", "ST": "BeiJing" } ] } EOF
3、生成證書
# 生成 Etcd根證書
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
# 生成 Etcd服務證書
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
生成后可以看到生成了4個pem文件
ls *pem
1.4.2 解壓etcd
以下部署步驟在規划的三個etcd節點操作一樣,唯一不同的是etcd配置文件中的服務器IP要寫當前的。
二進制包下載地址:https://github.com/etcd-io/etcd/releases/
cd /usr/local/src/
wget https://github.com/etcd-io/etcd/releases/download/v3.3.12/etcd-v3.3.12-linux-amd64.tar.gz
mkdir /opt/etcd/{bin,cfg,ssl} -p
tar zxvf etcd-v3.3.12-linux-amd64.tar.gz
mv etcd-v3.3.12-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/
1.4.3 創建etcd配置文件
cat > /opt/etcd/cfg/etcd <<EOF #[Member] ETCD_NAME="etcd01" ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="https://172.31.50.170:2380" ETCD_LISTEN_CLIENT_URLS="https://172.31.50.170:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.31.50.170:2380" ETCD_ADVERTISE_CLIENT_URLS="https://172.31.50.170:2379" ETCD_INITIAL_CLUSTER="etcd01=https://172.31.50.170:2380,etcd02=https://172.31.50.101:2380,etcd03=https://172.31.58.221:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="new" EOF
注意:每個節點上標黃的需要調整對應的值。
參數說明:
ETCD_NAME 節點名稱
ETCD_DATA_DIR 數據目錄
ETCD_LISTEN_PEER_URLS 集群通信監聽地址
ETCD_LISTEN_CLIENT_URLS 客戶端訪問監聽地址
ETCD_INITIAL_ADVERTISE_PEER_URLS 集群通告地址
ETCD_ADVERTISE_CLIENT_URLS 客戶端通告地址
ETCD_INITIAL_CLUSTER 集群節點地址
ETCD_INITIAL_CLUSTER_TOKEN 集群Token
ETCD_INITIAL_CLUSTER_STATE 加入集群的當前狀態,new是新集群,existing表示加入已有集群
1.4.4 systemd管理etcd
vim /usr/lib/systemd/system/etcd.service
[Unit] Description=Etcd Server After=network.target After=network-online.target Wants=network-online.target [Service] Type=notify EnvironmentFile=/opt/etcd/cfg/etcd ExecStart=/opt/etcd/bin/etcd \ --name=${ETCD_NAME} \ --data-dir=${ETCD_DATA_DIR} \ --listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \ --listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \ --advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \ --initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \ --initial-cluster=${ETCD_INITIAL_CLUSTER} \ --initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \ --initial-cluster-state=new \ --cert-file=/opt/etcd/ssl/server.pem \ --key-file=/opt/etcd/ssl/server-key.pem \ --peer-cert-file=/opt/etcd/ssl/server.pem \ --peer-key-file=/opt/etcd/ssl/server-key.pem \ --trusted-ca-file=/opt/etcd/ssl/ca.pem \ --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
1.4.5 拷貝證書
把剛才生成的證書拷貝到配置文件中的位置。
#在生成證書節點上可直接執行:
cp ~/etcd_ca/*.pem /opt/etcd/ssl/
#其他2個節點遠程復制過去:
scp ~/etcd_ca/*.pem root@172.31.50.101:/opt/etcd/ssl
scp ~/etcd_ca/*.pem root@172.31.55.50:/opt/etcd/ssl
1.4.6 開放防火牆端口
三個節點防火牆都開放端口:2379、2380端口
vim /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2379 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2380 -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
1.4.7 啟動etcd並設置自啟
systemctl daemon-reload
systemctl start etcd && systemctl enable etcd && systemctl status etcd
#注意:如果有問題,查看日志:tail /var/log/messages
1.4.8 驗證集群
/opt/etcd/bin/etcdctl \
--ca-file=/opt/etcd/ssl/ca.pem --cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--endpoints="https://172.31.50.170:2379,https://172.31.50.101:2379,https://172.31.58.221:2379" \
cluster-health
如果輸出上面截圖信息,就說明集群部署成功。
1.4.9 etcdctl命令加入環境變量
vim /etc/profile
export PATH=/opt/etcd/bin:$PATH
#重新加載生效:
source /etc/profile
#下次登入還需要再次執行,所以把source命令添加到/etc/bashrc文件,這樣會為每一個用戶都執行這個命令。
echo "source /etc/profile" >> /etc/bashrc
1.5 Master節點部署組件
在部署Kubernetes之前一定要確保etcd是正常工作的,無特殊說明則需在三個master節點上操作。
1.5.1 生成證書
之前在master1節點的根目錄etcd_ca下生成過etcd的證書,為了避免證書混亂,在根目錄下新建目錄存放新的證書。
cd
mkdir k8s_ca
cd k8s_ca/
1、生成CA證書
cat > ca-config.json <<EOF { "signing": { "default": { "expiry": "87600h" }, "profiles": { "kubernetes": { "expiry": "87600h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } } EOF
cat > ca-csr.json <<EOF { "CN": "kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "ST": "Beijing", "O": "k8s", "OU": "System" } ] } EOF
#執行下面命令生成
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
2、生成apiserver證書
cat > server-csr.json <<EOF { "CN": "kubernetes", "hosts": [ "10.0.0.1", "127.0.0.1", "k8s-api-6443-c8528735cd54031c.elb.cn-north-1.amazonaws.com.cn", "172.31.50.170", "172.31.50.101", "172.31.58.221", "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" } ] } EOF
說明:10段為虛擬IP段,還需添加上負載均衡IP(aws則需要先配置好1.5節內容),以及apiserver集群IP。
#執行下面命令生成
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
3、生成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" } ] } EOF
#執行下面命令生成
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
4、生成admin證書
cat > admin-csr.json <<EOF { "CN": "admin", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "system:masters", "OU": "System" } ] } EOF
說明:后續 kube-apiserver 使用 RBAC 對客戶端(如 kubelet、kube-proxy、Pod)請求進行授權;kube-apiserver 預定義了一些 RBAC 使用的 RoleBindings,如 cluster-admin 將 Group system:masters 與 Role cluster-admin 綁定,該 Role 授予了調用kube-apiserver 的所有 API的權限;O 指定該證書的 Group 為 system:masters,kubelet 使用該證書訪問 kube-apiserver 時 ,由於證書被 CA 簽名,所以認證通過,同時由於證書用戶組為經過預授權的 system:masters,所以被授予訪問所有 API 的權限;
注意:這個admin 證書,是將來生成管理員用的kube config 配置文件用的,現在我們一般建議使用RBAC 來對kubernetes 進行角色權限控制,kubernetes 將證書中的CN 字段作為User,O 字段作為 Group。
#執行下面命令生成
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
5、查看生成的證書
最終生成8個文件
admin-key.pem admin.pem ca-key.pem ca.pem kube-proxy-key.pem kube-proxy.pem server-key.pem server.pem
1.5.2 部署apiserver組件
此章節在所有master節點上操作。
下載二進制包頁面:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md
下載這個包(kubernetes-server-linux-amd64.tar.gz)就夠了,包含了所需的所有組件。地址:https://storage.googleapis.com/kubernetes-release/release/v1.14.1/kubernetes-server-linux-amd64.tar.gz
或者用上傳的七牛雲:https://img.yiyao.cc/kubernetes-server-linux-amd64.tar.gz
1、拷貝證書
mkdir /opt/kubernetes/{bin,cfg,ssl} -p
#拷貝證書
cp *pem /opt/kubernetes/ssl
#master2節點遠程復制過去:
scp *pem root@172.31.50.101:/opt/kubernetes/ssl
2、解壓文件
cd /usr/local/src
tar zxvf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
cp kube-apiserver kube-scheduler kube-controller-manager kubectl /opt/kubernetes/bin
3、創建token文件
cat > /opt/kubernetes/cfg/token.csv <<EOF bd41d77ac7cad4cfaa27f6403b1ccf16,kubelet-bootstrap,10001,"system:kubelet-bootstrap" EOF
說明:
第一列:隨機32位字符串,可自己命令生成:head -c 16 /dev/urandom | od -An -t x | tr -d ' '
第二列:用戶名
第三列:UID
第四列:用戶組
4、創建apiserver配置文件
配置好前面生成的證書,確保能連接etcd;address地址改成當前節點的IP。
vim /opt/kubernetes/cfg/kube-apiserver
KUBE_APISERVER_OPTS="--logtostderr=true \ --v=4 \ --etcd-servers=https://172.31.50.170:2379,https://172.31.50.101:2379,https://172.31.58.221:2379 \ --bind-address=172.31.50.170 \ --secure-port=6443 \ --advertise-address=172.31.50.170 \ --allow-privileged=true \ --service-cluster-ip-range=10.0.0.0/16 \ --enable-admission-plugins=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota,NodeRestriction \ --authorization-mode=RBAC,Node \ --enable-bootstrap-token-auth \ --token-auth-file=/opt/kubernetes/cfg/token.csv \ --service-node-port-range=30000-50000 \ --tls-cert-file=/opt/kubernetes/ssl/server.pem \ --tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \ --client-ca-file=/opt/kubernetes/ssl/ca.pem \ --service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \ --kubelet-client-certificate=/opt/kubernetes/ssl/admin.pem \ --kubelet-client-key=/opt/kubernetes/ssl/admin-key.pem \ --etcd-cafile=/opt/etcd/ssl/ca.pem \ --etcd-certfile=/opt/etcd/ssl/server.pem \ --etcd-keyfile=/opt/etcd/ssl/server-key.pem"
#參數說明:
--logtostderr 啟用日志
---v 日志等級
--etcd-servers etcd集群地址
--bind-address 監聽地址
--secure-port https安全端口
--advertise-address 集群通告地址
--allow-privileged 啟用授權
--service-cluster-ip-range Service虛擬IP地址段
--enable-admission-plugins 准入控制模塊
--authorization-mode 認證授權,啟用RBAC授權和節點自管理
--enable-bootstrap-token-auth 啟用TLS bootstrap功能,后面會講到
--token-auth-file token文件
--service-node-port-range Service Node類型默認分配端口范圍
5、systemd管理apiserver
vim /usr/lib/systemd/system/kube-apiserver.service
[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
6、啟動apiserver
systemctl daemon-reload
systemctl enable kube-apiserver
systemctl restart kube-apiserver
systemctl status kube-apiserver
7、開放防火牆端口
kube-apiserver默認啟動兩個端口6443、8080
vim /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
1.5.3 部署schduler組件
1、創建schduler配置文件
vim /opt/kubernetes/cfg/kube-scheduler
KUBE_SCHEDULER_OPTS="--logtostderr=true \ --v=4 \ --master=127.0.0.1:8080 \ --leader-elect"
#參數說明:
--master 連接本地apiserver
--leader-elect 當該組件啟動多個時,自動選舉(HA)
2、systemd管理schduler組件
vim /usr/lib/systemd/system/kube-scheduler.service
[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
3、啟動schduler
systemctl daemon-reload
systemctl enable kube-scheduler
systemctl restart kube-scheduler
systemctl status kube-scheduler
4、開放防火牆端口
schduler默認啟動端口10251
vim /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10251 -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
1.5.4 部署controller-manager組件
1、創建controller-manager配置文件
vim /opt/kubernetes/cfg/kube-controller-manager
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=true \ --v=4 \ --master=127.0.0.1:8080 \ --leader-elect=true \ --address=127.0.0.1 \ --service-cluster-ip-range=10.0.0.0/16 \ --cluster-cidr=10.10.0.0/16 \ --cluster-name=kubernetes \ --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"
2、systemd管理controller-manager組件
vim /usr/lib/systemd/system/kube-controller-manager.service
[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
3、啟動controller-manager
systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl restart kube-controller-manager
systemctl status kube-controller-manager
4、開放防火牆端口
schduler默認啟動端口10257
vim /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10257 -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
1.5.5 查看集群組件狀態
/opt/kubernetes/bin/kubectl get cs
如上輸出說明組件都正常。另一個Master節點部署方式一樣。
可以把kubectl命令加入到環境變量
vim /etc/profile
export PATH=/opt/kubernetes/bin:$PATH
#重新加載生效
source /etc/profile
1.6 Master高可用
所謂的Master HA,其實就是APIServer的HA,Master的其他組件controller-manager、scheduler都是可以通過etcd做選舉(--leader-elect),而APIServer設計的就是可擴展性,所以做到APIServer很容易,只要前面加一個負載均衡輪訓轉發請求即可。如果是aws可以采用負載均衡器實現,如果是實體機可以采用Haproxy+keeplive實現。下面分別對這兩種方法進行驗證。
1.6.1 方法一:aws負載均衡器
1、配置aws負載均衡
2、配置路由
3、配置路由,選擇實例中的6443端口
4、注冊目標,選擇3個master實例
5、下一步審核即可,最后會創建一個lb,並且會分配到一個域名
6、本地用tcping命令測試,可發現已經代理了6443端口
tcping k8s-api-6443-c8528735cd54031c.elb.cn-north-1.amazonaws.com.cn 6443
后續kubelet指定apiserver的地址時候,可以寫該域名。
1.6.2 方法二:Haproxy+keepalive
在所有Master節點上部署Haproxy+keepalive。(適應於非雲平台部署,因雲平台不支持keepalive)
1、部署haproxy
所有master節點上部署,配置保持一樣。
1)安裝haproxy
yum -y install haproxy
2)修改配置文件
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg-back
vim /etc/haproxy/haproxy.cfg
global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemon stats socket /var/lib/haproxy/stats defaults mode tcp log global option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.0/8 option redispatch retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s maxconn 3000 frontend main *:16443 acl url_static path_beg -i /static /images /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js use_backend static if url_static default_backend kube-apiserver backend static balance roundrobin server static 127.0.0.1:4331 check backend kube-apiserver balance roundrobin server matser1 172.31.50.170:6443 check server master2 172.31.50.101:6443 check
#注意:修改標紅的地方
1、defaults 模塊中的 mode http 要改為 tcp(或者在下面的 frontend 和 backend 模塊中單獨定義 mode tcp )如果不改,后續 kubectl get node 會處於 NotReady 狀態。
2、frontend 端口需指定非 6443 端口,要不然其他 master 節點會啟動異常(如果 haproxy 單獨主機,則可用 6443 端口)
說明:配置文件可以拷貝其他節點,配置文件保持一樣。
3)啟動haproxy
systemctl start haproxy
systemctl enable haproxy
systemctl status haproxy
4)配置防火牆
vim /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp --dport 16443 -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
2、 部署keepalive
1)安裝keepalive
yum install -y keepalived
2)修改配置文件
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf-back
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived global_defs { router_id LVS_1 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.10.24/24 } }
說明:
1、global_defs 只保留 router_id(每個節點都不同);
2、修改 interface(vip綁定的網卡),及 virtual_ipaddress(vip地址及掩碼長度);
3、刪除后面的示例
4、其他節點只需修改 state 為 BACKUP,優先級 priority 低於100即可。
3)啟動keeplive
systemctl start keepalived
systemctl enable keepalived
systemctl status keepalived
4)配置防火牆
防火牆要對vrrp協議進行開放
vim /etc/sysconfig/iptables
-A INPUT -p vrrp -j ACCEPT
#重啟防火牆
service iptables restart && service iptables save
5)查看狀態
ip addr show ens33
可以看到vip只在一台機器上;如果兩個機器都有vip,可能是防火牆攔截了vrrp協議。
1.7 Node節點部署組件
Master apiserver啟用TLS認證后,Node節點kubelet組件想要加入集群,必須使用CA簽發的有效證書才能與apiserver通信,當Node節點很多時,簽署證書是一件很繁瑣的事情,因此有了TLS Bootstrapping機制,kubelet會以一個低權限用戶自動向apiserver申請證書,kubelet的證書由apiserver動態簽署。
1.7.1 認證流程
認證大致工作流程如圖所示:
1.7.2 用戶綁定系統集群角色
在msater1上面執行,將kubelet-bootstrap用戶綁定到系統集群角色:
/opt/kubernetes/bin/kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
1.7.3 創建kubeconfig文件
在mster1生成kubernetes證書的目錄下執行以下命令生成kubeconfig文件,其他節點拷貝過去即可。
cd /root/k8s_ca/
1、創建bootstrapping kubeconfig文件
1)指定apiserver 內網負載均衡地址端口(vip:port),以及token值
KUBE_APISERVER="https://k8s-api-6443-c8528735cd54031c.elb.cn-north-1.amazonaws.com.cn:6443" BOOTSTRAP_TOKEN=bd41d77ac7cad4cfaa27f6403b1ccf16
說明: KUBE_APISERVER 參數對應的就是 AWS 中設置的負載均衡地址,或者對應 keepalive 的 vip 地址。
2)設置集群參數
/opt/kubernetes/bin/kubectl config set-cluster kubernetes \ --certificate-authority=./ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=bootstrap.kubeconfig
3)設置客戶端認證參數
/opt/kubernetes/bin/kubectl config set-credentials kubelet-bootstrap \ --token=${BOOTSTRAP_TOKEN} \ --kubeconfig=bootstrap.kubeconfig
4)設置上下文參數
/opt/kubernetes/bin/kubectl config set-context default \ --cluster=kubernetes \ --user=kubelet-bootstrap \ --kubeconfig=bootstrap.kubeconfig
5)設置默認上下文
/opt/kubernetes/bin/kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
2、創建kube-proxy kubeconfig文件
1)設置集群參數
/opt/kubernetes/bin/kubectl config set-cluster kubernetes \ --certificate-authority=./ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=kube-proxy.kubeconfig
2)設置客戶端認證參數
/opt/kubernetes/bin/kubectl config set-credentials kube-proxy \ --client-certificate=./kube-proxy.pem \ --client-key=./kube-proxy-key.pem \ --embed-certs=true \ --kubeconfig=kube-proxy.kubeconfig
3)設置上下文參數
/opt/kubernetes/bin/kubectl config set-context default \ --cluster=kubernetes \ --user=kube-proxy \ --kubeconfig=kube-proxy.kubeconfig
4)設置默認上下文
/opt/kubernetes/bin/kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
3、查看生成的kubeconfig文件
ls *kubeconfig
bootstrap.kubeconfig kube-proxy.kubeconfig
4、拷貝kubeconfig文件
將這兩個文件拷貝到Node節點/opt/kubernetes/cfg目錄下。
需要在node節點上新建目錄
mkdir /opt/kubernetes/{bin,cfg,ssl} -p
scp *kubeconfig root@172.31.55.50:/opt/kubernetes/cfg
scp *kubeconfig root@172.31.55.0:/opt/kubernetes/cfg
1.7.4 Node節點安裝Docker
在所有node節點安裝docker。
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce -y
systemctl start docker
systemctl enable docker
注意:得提前安裝好docker環境,要不然kubelet啟動不起來。
1.7.5 部署kubelet組件
無特殊說明,則默認在所有node節點上都部署。
1、拷貝kubelet和kube-proxy文件
從msater1上下載解壓的二進制包中的kubelet和kube-proxy拷貝到node節點的/opt/kubernetes/bin目錄下。
cd /usr/local/src
wget https://img.yiyao.cc/kubernetes-server-linux-amd64.tar.gz
tar -zxvf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
scp kubelet kube-proxy root@172.31.55.50:/opt/kubernetes/bin
scp kubelet kube-proxy root@172.31.55.0:/opt/kubernetes/bin
2、創建kubelet配置文件
vim /opt/kubernetes/cfg/kubelet
KUBELET_OPTS="--logtostderr=true \ --v=4 \ --hostname-override=k8snode1 \ --kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \ --bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \ --config=/opt/kubernetes/cfg/kubelet.config \ --cert-dir=/opt/kubernetes/ssl \ --client-ca-file=/opt/kubernetes/ssl/ca.pem \ --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
並且需要拷貝ca證書到/opt/kubernetes/ssl目錄下。
參數說明:
--hostname-override 在集群中顯示的主機名
--kubeconfig 指定kubeconfig文件位置,會自動生成
--bootstrap-kubeconfig 指定剛才生成的bootstrap.kubeconfig文件
--cert-dir 頒發證書存放位置
--pod-infra-container-image 管理Pod網絡的鏡像
3、創建kubelet.config配置文件
注意格式縮進
vim /opt/kubernetes/cfg/kubelet.config
kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 address: 172.31.55.50 port: 10250 readOnlyPort: 10255 cgroupDriver: cgroupfs clusterDNS: ["10.0.0.2"] clusterDomain: cluster.local. failSwapOn: false authentication: anonymous: enabled: true webhook: enabled: false
4、systemd管理kubelet組件
vim /usr/lib/systemd/system/kubelet.service
[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
5、啟動kubelet組件
systemctl daemon-reload
systemctl enable kubelet #開機自啟
systemctl restart kubelet #啟動
systemctl status kubelet #啟動狀態
會占用10250端口(需要在iptables設置開放,協議為tcp),要不然進入容器會報錯:
Error from server: error dialing backend: dial tcp 172.31.55.50:10250: connect: no route to host
這里是把所有 node 節點的iptables配置文件都清空的,默認所有端口開放,所以不用單獨設置。
6、在Master審批Node加入集群
啟動后還沒加入到集群中,需要手動允許該節點才可以。
1)在Master節點查看請求簽名的Node:
/opt/kubernetes/bin/kubectl get csr
可以看到有兩個節點的簽名請求,如果執行命令后提示:No resources found,可去node節點查看messages日志。
2)在Master節點批准簽名
/opt/kubernetes/bin/kubectl certificate approve node-csr-SJvxb_b-sBqfsLo-ILzaQm_6S9DH_w3THpLGCLNkLDU
/opt/kubernetes/bin/kubectl certificate approve node-csr-bF-v5M0Nv3niDVVEGf1YdlwYvRoRrjhR82jlPiXiOvU
3)查看簽名狀態
/opt/kubernetes/bin/kubectl get node
狀態都為Ready。
1.7.6 部署kube-proxy組件
在所有node節點上部署。
1、創建kube-proxy配置文件
vim /opt/kubernetes/cfg/kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true \ --v=4 \ --hostname-override=k8snode1 \ --cluster-cidr=10.10.0.0/16 \ --kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
注意:cluster-cidr不能與service-cidr還有主機的cidr網段重疊。
2、systemd管理kube-proxy組件
vim /usr/lib/systemd/system/kube-proxy.service
[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
3、啟動kube-proxy組件
systemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy
systemctl status kube-proxy
#會占用兩個端口:10249、10256
1.7.7 確認node能夠訪問443端口
tcping 10.0.0.1 443
到此部署node完成。
1.8 部署Calico網絡
若無特殊說明,都需在master1節點上操作。配置參考:https://www.jianshu.com/p/5e9e2e5312d9
1.8.1 工作原理
1、特點優勢
1) 純三層的SDN 實現,它基於BPG 協議和Linux自身的路由轉發機制,不依賴特殊硬件,容器通信也不依賴iptables NAT(使用直接路由方式實現通行)或Tunnel 等技術,帶寬性能接近主機。
2)能夠方便的部署在物理服務器、虛擬機或者容器環境下。
3)同時calico自帶的基於iptables的ACL管理組件非常靈活,能夠滿足比較復雜的安全隔離需求。支持Kubernetes networkpolicy概念
4)容器間網絡三層隔離,無需要擔心arp風暴
5)自由控制的policy規則
6)通過iptables和kernel包轉發,效率高,損耗低
2、calico組件
1)Felix:主要負責路由配置以及ACLS規則的配置以及下發,它存在在每個node節點上。
2)etcd:分布式鍵值存儲,主要負責網絡元數據一致性,確保Calico網絡狀態的准確性,可以與kubernetes共用;
3)BGPClient(BIRD), 主要負責把 Felix寫入 kernel的路由信息分發到當前 Calico網絡,確保 workload間的通信的有效性;
4)BGPRoute Reflector(BIRD), 大規模部署時使用,摒棄所有節點互聯的mesh模式,通過一個或者多個 BGPRoute Reflector 來完成集中式的路由分發;
如下圖:
1.8.2 配置calico
部署calico需要在kubernetes集群部署好后操作,只需在master1上操作
1、下載yaml文件
mkdir /opt/calico/{bin,deploy} -p
cd /opt/calico/deploy
wget https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/calico.yaml
2、配置calico
部署之前需要檢查3處
1)配置ConfigMap中etcd集群etcd_endpoints
etcd_endpoints: "https://172.31.50.170:2379,https://172.31.50.101:2379,https://172.31.58.221:2379"
2)配置Calico訪問etcd集群的TLS證書,默認已經給出了訪問etcd的TLS文件所在容器路徑了,填進去即可(注意:此配置為容器內部讀取的變量,所以證書路徑為容器路徑,而不是宿主機路徑,不要修改為別的路徑。)。
etcd_ca: "/calico-secrets/etcd-ca" etcd_cert: "/calico-secrets/etcd-cert" etcd_key: "/calico-secrets/etcd-key"
3)在Secret部分中,是采用創建secret的方式來配置TLS文件,在這里我們改用hostPath掛載TLS文件方式
#注釋掉的Secret部分的TLS部分,默認為注釋可不用改
#設置calico-node以hostpath的方式來掛載TLS文件,找到DaemonSet部分,設置為如下:
- name: etcd-certs
hostPath:
path: /opt/etcd/ssl
#設置calico-kube-controllers以hostpath掛載TLS文件,找到Deployment部分,設置為如下:
- name: etcd-certs
hostPath:
path: /opt/etcd/ssl
4)修改deamonset部分CALICO_IPV4POOL_CIDR變量
value: "10.10.0.0/16"
說明:
1、CALICO_IPV4POOL_CIDR: Calico IPAM的IP地址池,Pod的IP地址將從該池中進行分配(后續需要更改這個IP池,可參考1.8.9小節)。這個值需要同kube-controller-manager和kebe-proxy定義的--cluster-cidr值一致,但是得和apiserver中的service-cluster-ip-range值不同。
2、ALICO_IPV4POOL_IPIP:是否啟用IPIP模式,啟用IPIP模式時,Calico將在node上創建一個tunl0的虛擬隧道。
3、FELIX_LOGSEVERITYSCREEN: 日志級別。
4、IP Pool可以使用兩種模式:BGP或IPIP。使用IPIP模式時,設置 CALICO_IPV4POOL_IPIP="always",不使用IPIP模式時,設置為"off",此時將使用BGP模式。
5、IPIP:ipip是在宿主機網絡不完全支持bgp時,一種妥協的overlay機制,在宿主機創建1個”tunl0”虛擬端口;設置為false時,路由即純bgp模式,理論上ipip模式的網絡傳輸性能低於純bgp模式;設置為true時,又分ipip always模式(純ipip模式)與ipip cross-subnet模式(ipip-bgp混合模式),后者指“同子網內路由采用bgp,跨子網路由采用ipip”
1.8.3 修改kubelet
在每個node節點上操作
#kubelet啟動服務中增加--network-plugin、--cni-conf-dir、--cni-bin-dir三個配置參數
vim /opt/kubernetes/cfg/kubelet
--network-plugin=cni \ --cni-conf-dir=/etc/cni/net.d \ --cni-bin-dir=/opt/cni/bin \
#重啟kubelet
systemctl daemon-reload && systemctl restart kubelet && systemctl status kubelet
1.8.4 拷貝etcd的TLS授權文件
在各node節點操作,把master上的etcd證書全部復制到所有node的目錄下(步驟略),然后重命名一下(這里復制一份,因為后面安裝calicoctl工具需要原來的證書名字):
mkdir /opt/etcd/ssl -p
cd /opt/etcd/ssl
cp ca.pem etcd-ca
cp server-key.pem etcd-key
cp server.pem etcd-cert
1.8.5 部署calico組件
#部署calico
kubectl apply -f calico.yaml
#查看calico服務
calico-node用的是daemonset,會在每個node上啟動; calico-kube-controllers用的是Deployment,會在某個node啟動。
kubectl get deployment,pod -n kube-system
#同時在node節點上可以看到已經生成了tunl0隧道網卡
1.8.6 驗證網絡功能
新建一個nginx pod
cat > my-nginx.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: replicas: 2 selector: matchLabels: k8s-app: my-nginx template: metadata: labels: k8s-app: my-nginx spec: containers: - name: my-nginx image: nginx:1.9 ports: - containerPort: 80 EOF
#創建pod
kubectl create -f my-nginx.yaml
#創建my-nginx服務
kubectl expose deploy my-nginx
#查看pod
kubectl get svc,pod --all-namespaces -o wide
看到可以給pod分配到IP,說明calico配置好了。(默認所有的pod都是互通的,包括跨node。可以用 route -n 查看有通往其他 node 的 tunl0 路由)
1.8.7 安裝管理工具calicoctl
在所有master和node節點上操作
1、下載calicoctl
cd /opt/calico/bin (從節點:mkdir -p /opt/calico/bin && cd /opt/calico/bin)
wget https://github.com/projectcalico/calicoctl/releases/download/v3.6.0/calicoctl
chmod +x calicoctl
#添加calicoctl 命令加入到環境變量
echo "export PATH=/opt/calico/bin:\$PATH" >>/etc/profile
#重新加載生效
source /etc/profile
2、編寫calicoctl的配置文件
#默認為下面的路徑,不要改動
mkdir /etc/calico
vim /etc/calico/calicoctl.cfg
apiVersion: projectcalico.org/v3 kind: CalicoAPIConfig metadata: spec: datastoreType: "etcdv3" etcdEndpoints: "https://172.31.50.170:2379,https://172.31.50.101:2379,https://172.31.58.221:2379" etcdKeyFile: "/opt/etcd/ssl/server-key.pem" etcdCertFile: "/opt/etcd/ssl/server.pem" etcdCACertFile: "/opt/etcd/ssl/ca.pem"
3、查看calico狀態
#查看已注冊的節點列表
calicoctl get node
#查看默認IP池
calicoctl get ippool -o wide
#查看節點狀態為Established(這個必須要在每個node節點上安裝calicoctl,在node上執行,並且只能看到非本節點的)。
calicoctl node status
到此部署calico完成。
1.8.8 更換IP池方法
參考官網:https://docs.projectcalico.org/v3.6/networking/changing-ip-pools
1、前提條件
在Kubernetes中,確保以下所有三個參數必須等於或包含Calico IP池CIDR
kube-apiserver: --pod-network-cidr
kube-proxy: --cluster-cidr
kube-controller-manager: --cluster-cidr
說明:我設置了apiserver后,apiserver啟動失敗,暫不設置。
2、添加新的IP池
#查看默認的IP池
calicoctl get ippool -o wide
#創建新的IP池
calicoctl create -f -<<EOF apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: new-pool spec: cidr: 10.10.0.0/16 ipipMode: Always natOutgoing: true EOF
#查看到有2個IP池
3、禁用舊的IP池
首先將IP池定義保存到本地磁盤
cd /opt/calico/deploy
calicoctl get ippool -o yaml > pool.yaml
#編輯pool.yaml文件,添加disabled: true到default-ipv4-ippoolIP池,最終文件內容如下:
apiVersion: projectcalico.org/v3 items: - apiVersion: projectcalico.org/v3 kind: IPPool metadata: creationTimestamp: 2019-04-29T03:22:59Z name: default-ipv4-ippool resourceVersion: "82916" uid: 16db9294-6a2e-11e9-b48f-0225173d78b8 spec: blockSize: 26 cidr: 10.0.0.0/24 ipipMode: Always natOutgoing: true nodeSelector: all() disabled: true - apiVersion: projectcalico.org/v3 kind: IPPool metadata: creationTimestamp: 2019-05-06T05:32:27Z name: new-pool resourceVersion: "1086435" uid: 55a21a46-6fc0-11e9-bf99-02b325080bdc spec: blockSize: 26 cidr: 10.10.0.0/16 ipipMode: Always natOutgoing: true nodeSelector: all() kind: IPPoolList metadata: resourceVersion: "1086435"
#應用更改
calicoctl apply -f pool.yaml
#再查看IP池狀態
calicoctl get ippool -o wide
4、重新創建從舊IP池分配地址的所有現有工作負載
#查看現有的工作負載
kubectl get svc,pod --all-namespaces -o wide
#重新創建所有現有工作負載
kubectl delete pod -n online online-nginx-776bbdf4f8-2fl95
kubectl delete pod -n online online-nginx-776bbdf4f8-sznmg
5、刪除舊的IP池
calicoctl delete pool default-ipv4-ippool
1.8.9 卸載calico方法
1、master上執行刪除pod
kubectl delete -f calico.yaml
2、node上刪除ipip模塊(對應的網卡和路由也會被刪除)
modprobe -r ipip
3、node上刪除生成的文件
rm -rf /etc/cni/net.d/ && rm -rf /opt/cni/bin/
4、重啟node
reboot
二、部署CoreDNS
在master1上操作,參考:https://www.zrq.org.cn/post/k8s%E9%83%A8%E7%BD%B2coredns/
2.1 下載配置文件
從官網下載配置文件(https://github.com/coredns/deployment/tree/master/kubernetes),找到 coredns.yam.sed 和 deploy.sh 兩個文件,下載后存放在下面的新建目錄下
mkdir /opt/coredns && cd /opt/coredns/
wget https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/deploy.sh
wget https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/coredns.yaml.sed
chmod +x deploy.sh
2.2 修改部署文件
由於是二進制部署的集群,不包含kube-dns,故不需從kube-dns轉到coredns。
1、先查看集群的CLUSTERIP網段
kubectl get svc
2、修改部署文件
修改$DNS_DOMAIN、$DNS_SERVER_IP變量為實際值,並修改image后面的鏡像。
這里直接用deploy.sh腳本進行修改:
./deploy.sh -s -r 10.0.0.0/16 -i 10.0.0.2 -d cluster.local > coredns.yaml
注意:網段為10.0.0.0/16(同apiserver定義的service-cluster-ip-range值,非kube-proxy中的cluster-cidr值),DNS的地址設置為10.0.0.2
3、修改前后的文件對比
diff coredns.yaml coredns.yaml.sed
附:生成的 coredns.yaml文件,注意標黃位置。
apiVersion: v1 kind: ServiceAccount metadata: name: coredns namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: kubernetes.io/bootstrapping: rbac-defaults name: system:coredns rules: - apiGroups: - "" resources: - endpoints - services - pods - namespaces verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" labels: kubernetes.io/bootstrapping: rbac-defaults name: system:coredns roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:coredns subjects: - kind: ServiceAccount name: coredns namespace: kube-system --- apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health ready kubernetes cluster.local 10.0.0.0/16 { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance } --- apiVersion: apps/v1 kind: Deployment metadata: name: coredns namespace: kube-system labels: k8s-app: kube-dns kubernetes.io/name: "CoreDNS" spec: replicas: 2 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 selector: matchLabels: k8s-app: kube-dns template: metadata: labels: k8s-app: kube-dns spec: priorityClassName: system-cluster-critical serviceAccountName: coredns tolerations: - key: "CriticalAddonsOnly" operator: "Exists" nodeSelector: beta.kubernetes.io/os: linux containers: - name: coredns image: coredns/coredns:1.5.0 imagePullPolicy: IfNotPresent resources: limits: memory: 170Mi requests: cpu: 100m memory: 70Mi args: [ "-conf", "/etc/coredns/Corefile" ] volumeMounts: - name: config-volume mountPath: /etc/coredns readOnly: true ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP - containerPort: 9153 name: metrics protocol: TCP securityContext: allowPrivilegeEscalation: false capabilities: add: - NET_BIND_SERVICE drop: - all readOnlyRootFilesystem: true livenessProbe: httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 readinessProbe: httpGet: path: /ready port: 8181 scheme: HTTP dnsPolicy: Default volumes: - name: config-volume configMap: name: coredns items: - key: Corefile path: Corefile --- apiVersion: v1 kind: Service metadata: name: kube-dns namespace: kube-system annotations: prometheus.io/port: "9153" prometheus.io/scrape: "true" labels: k8s-app: kube-dns kubernetes.io/cluster-service: "true" kubernetes.io/name: "CoreDNS" spec: selector: k8s-app: kube-dns clusterIP: 10.0.0.2 ports: - name: dns port: 53 protocol: UDP - name: dns-tcp port: 53 protocol: TCP - name: metrics port: 9153 protocol: TCP
#說明:
$DNS_DOMAIN 被修改為:cluster.local
image 這邊用的是:coredns/coredns:1.5.0
$DNS_SERVER_IP 被修改為:10.0.0.2
2.3 部署coredns
#部署
kubectl create -f coredns.yaml
#查看
kubectl get svc,pod -n kube-system
2.4 修改kubelet的dns服務參數
在所有node節點上操作,添加以下參數
vim /opt/kubernetes/cfg/kubelet
--cluster-dns=10.0.0.2 \ --cluster-domain=cluster.local. \ --resolv-conf=/etc/resolv.conf \
#重啟kubelet 並查看狀態
systemctl daemon-reload && systemctl restart kubelet && systemctl status kubelet
2.5 驗證CoreDNS服務解析
2.5.1 使用dnstools測試效果
#在master上操作,注意:busybox不能用高版本,要用低版本測試。
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
nslookup kubernetes.default
nslookup www.baidu.com
輸出結果如上,說明coredns可以解析成功。
cat /etc/resolv.conf
如上,每個pod都會在resolv.conf文件中聲明dns地址。
2.5.2 測試namespace域名互通
1.8.7小節已經在默認namespace:default中創建好了my-nginx,現在我們新建一個namespace:online,並創建online-nginx服務
1、創建namespace
kubectl create namespace online
2、部署online-nginx
cat >online-nginx.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: online-nginx namespace: online spec: replicas: 2 selector: matchLabels: k8s-app: online-nginx template: metadata: labels: k8s-app: online-nginx spec: containers: - name: online-nginx image: nginx:1.9 ports: - containerPort: 80 EOF
kubectl create -f online-nginx.yaml
kubectl expose deploy online-nginx -n online
3、運行curl工具測試
kubectl run curl --image=radial/busyboxplus:curl --namespace="online" --restart=Never --rm -it
nslookup kubernetes.default
curl my-nginx.default
curl online-nginx
說明:也可以指定namespace,訪問之前的my-nginx域名地址,也可以訪問同一namespace的pod。說明在不同的namespace上是互通的。
2.6 訪問容器報錯解決
[root@centos7 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-dbddb74b8-s7lp5 1/1 Running 1 22h
nginx-dbddb74b8-znxz5 1/1 Running 1 22h
如下發現執行查看資源報錯,不能進入容器。報錯:
[root@centos7 ~]# kubectl exec -it nginx-dbddb74b8-s7lp5 sh
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
原因:2.7.4中kubelet.config定義了:沒有進行身份驗證方法的對kubelet的HTTPS端點的請求將被視為匿名請求,並提供用戶名system:anonymous 和組system:unauthenticated。所以提示anonymous用戶沒有權限。
解決(官方推薦):啟動apiserver時指定admin賬戶證書授權
1)配置 kube-apiserver
vim /opt/kubernetes/cfg/kube-apiserver
--kubelet-client-certificate=/opt/kubernetes/ssl/admin.pem \
--kubelet-client-key=/opt/kubernetes/ssl/admin-key.pem \
#重啟 kube-apiserver
systemctl daemon-reload && systemctl restart kube-apiserver && systemctl status kube-apiserver
2)配置kubelet,從master復制apiserver中的ca證書到node上
vim /opt/kubernetes/cfg/kubelet
--client-ca-file=/opt/kubernetes/ssl/ca.pem \
#重啟 kube-apiserver
systemctl daemon-reload && systemctl restart kubelet && systemctl status kubelet
三、部署高可用Ingress
3.1 Ingress簡介
3.1.1需求
coredns是實現pods之間通過域名訪問,如果外部需要訪問service服務,需訪問對應的NodeIP:Port。但是由於NodePort需要指定宿主機端口,一旦服務多起來,多個端口就難以管理。那么,這種情況下,使用Ingress暴露服務更加合適。
3.1.2 Ingress組件說明
使用Ingress時一般會有三個組件:反向代理負載均衡器、Ingress Controller、Ingress
1、反向代理負載均衡器
反向代理負載均衡器很簡單,說白了就是 nginx、apache 等中間件,新版k8s已經將Nginx與Ingress Controller合並為一個組件,所以Nginx無需單獨部署,只需要部署Ingress Controller即可。在集群中反向代理負載均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等方式
2、Ingress Controller
Ingress Controller 實質上可以理解為是個監視器,Ingress Controller 通過不斷地跟 kubernetes API 打交道,實時的感知后端 service、pod 等變化,比如新增和減少 pod,service 增加與減少等;當得到這些變化信息后,Ingress Controller 再結合下文的 Ingress 生成配置,然后更新反向代理負載均衡器,並刷新其配置,達到服務發現的作用
3、Ingress
Ingress 簡單理解就是個規則定義;比如說某個域名對應某個 service,即當某個域名的請求進來時轉發給某個 service;這個規則將與 Ingress Controller 結合,然后 Ingress Controller 將其動態寫入到負載均衡器配置中,從而實現整體的服務發現和負載均衡
整體關系如下圖所示:
從上圖中可以很清晰的看到,實際上請求進來還是被負載均衡器攔截,比如 nginx,然后 Ingress Controller 通過跟 Ingress 交互得知某個域名對應哪個 service,再通過跟 kubernetes API 交互得知 service 地址等信息;綜合以后生成配置文件實時寫入負載均衡器,然后負載均衡器 reload 該規則便可實現服務發現,即動態映射。
3.1.3 Nginx-Ingress工作原理
ingress controller通過和kubernetes api交互,動態的去感知集群中ingress規則變化;然后讀取它,按照自定義的規則,規則就是寫明了哪個域名對應哪個service,生成一段nginx配置;再寫到nginx-ingress-control的pod里,這個Ingress controller的pod里運行着一個Nginx服務,控制器會把生成的nginx配置寫入/etc/nginx.conf文件中;然后reload一下使配置生效。以此達到域名分配置和動態更新的問題。
說明:基於nginx服務的ingress controller根據不同的開發公司,又分為:
k8s社區的ingres-nginx(https://github.com/kubernetes/ingress-nginx)
nginx公司的nginx-ingress(https://github.com/nginxinc/kubernetes-ingress)
3.2.4 Ingress Controller高可用架構
作為集群流量接入層,Ingress Controller的高可用性顯得尤為重要,高可用性首先要解決的就是單點故障問題,一般常用的是采用多副本部署的方式,我們在Kubernetes集群中部署高可用Ingress Controller接入層同樣采用多節點部署架構,同時由於Ingress作為集群流量接入口,建議采用獨占Ingress節點的方式,以避免業務應用與Ingress服務發生資源爭搶。
如上述部署架構圖,由多個獨占Ingress實例組成統一接入層承載集群入口流量,同時可依據后端業務流量水平擴縮容Ingress節點。當然如果您前期的集群規模並不大,也可以采用將Ingress服務與業務應用混部的方式,但建議進行資源限制和隔離。
3.2 部署高可用Ingress
ingress的高可用的話,要可以通過把nginx-ingress-controller運行到指定添加標簽的幾個node節點上,然后再把這幾個node節點加入到LB中,然后對應的域名解析到該LB即可實現ingress的高可用。(注意:添加標簽的節點數量要大於等於集群Pod副本數,從而避免多個Pod運行在同一個節點上。不建議將Ingress服務部署到master節點上,盡量選擇worker節點添加標簽。)
以下無特殊說明,都在master1上操作,參考:https://www.cnblogs.com/terrycy/p/10048165.html
3.2.1 給node添加標簽
我這里在2個node上安裝nginx-ingress-controller,只需給這兩個node添加標簽
kubectl label node k8snode1 ingresscontroller=true
kubectl label node k8snode2 ingresscontroller=true
#查看標簽
kubectl get nodes --show-labels
附:
#刪除標簽
kubectl label node k8snode1 ingresscontroller-
#更新標簽
kubectl label node k8snode1 ingresscontroller=false --overwrite
3.2.2 下載yaml部署文件
下載地址:https://github.com/kubernetes/ingress-nginx/tree/master/deploy,有如下幾個yaml文件,我們只需要下載mandatory.yaml文件即可,它包含了其余4個文件的內容。
mkdir /opt/ingress && cd /opt/ingress/
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
3.2.3 修改yaml文件
1、修改Deployment為DaemonSet,並注釋掉副本數
kind: DaemonSet #replicas: 1
說明:默認kind: Deployment,replicas: 1,即在1個節點上啟動1個ingress-nginx controller Pod,所以需要修成DaemonSet,即為每一個節點都啟動一個pod。
DaemonSet和Deployment區別:Deployment 部署的副本 Pod 會分布在各個 Node 上,每個 Node 都可能運行好幾個副本。DaemonSet 的不同之處在於:每個 Node 上最多只能運行一個副本。
2、啟用hostNetwork網絡,並指定運行節點
hostNetwork暴露ingress-nginx controller的相關業務端口到主機,這樣node節點主機所在網絡的其他主機,都可以通過該端口訪問到此應用程序。
nodeSelector指定之前添加ingresscontroller=true標簽的node
hostNetwork: true nodeSelector: ingresscontroller: 'true'
3、修改鏡像地址,默認的鏡像地址下載了幾個小時都沒下載好
registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.24.1
可提前在node上下載鏡像
3.2.4 部署ingress
#部署
kubectl create -f mandatory.yaml
#查看ingress-controller
kubectl get ds -n ingress-nginx
kubectl get pods -n ingress-nginx -o wide
踩坑:pod無法創建,並且create的時候也沒有任何錯誤。
參考網上文章:https://www.liuyalei.top/1455.html 后,有提示報錯:Error creating: pods "nginx-ingress-controller-565dfd6dff-g977n" is forbidden: SecurityContext.RunAsUser is forbidden
解決:需要對准入控制器進行修改,取消SecurityContextDeny 的enable就行,然后重啟apiserver:
vim /opt/kubernetes/cfg/kube-apiserver
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
#重啟 kube-apiserver
systemctl daemon-reload && systemctl restart kube-apiserver && systemctl status kube-apiserver
3.3 驗證功能
3.3.1 創建測試用pod和server
vim nginx-static.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-static apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-static labels: name: nginx-static spec: replicas: 1 template: metadata: labels: name: nginx-static spec: containers: - name: nginx-static image: nginx:latest volumeMounts: - mountPath: /etc/localtime name: vol-localtime readOnly: true ports: - containerPort: 80 volumes: - name: vol-localtime hostPath: path: /etc/localtime --- apiVersion: v1 kind: Service metadata: name: nginx-static labels: name: nginx-static spec: ports: - port: 80 protocol: TCP targetPort: 80 name: http selector: name: nginx-static
#創建
kubectl create -f nginx-static.yaml
#查看服務和pod
可以看到部署到了k8smaster2(172.31.50.101)上
3.3.2 配置ingress
vim nginx-static-ingress.yaml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: submodule-checker-ingress spec: rules: - host: nginx.weave.pub http: paths: - backend: serviceName: nginx-static servicePort: 80
#應用ingress規則
kubectl create -f nginx-static-ingress.yaml
#查看ingress規則
kubectl get ingress -o wide
3.3.3 訪問
在其他端訪問,需要修改hosts文件,比如修改master1的hosts,給ingress服務端的IP,指定到自定義的域名。
172.31.55.50 k8snode3 nginx.weave.pub
#測試能否解析
curl nginx.weave.pub
訪問報錯:504 Gateway time out,這是因為nginx連接時間超時,默認是60s,設置大一點。
參考:https://github.com/kubernetes/ingress-nginx/issues/2007
解決:修改nginx-static-ingress.yaml文件,添加標紅處:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: submodule-checker-ingress annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-connect-timeout: "14400" nginx.ingress.kubernetes.io/proxy-send-timeout: "14400" nginx.ingress.kubernetes.io/proxy-read-timeout: "14400" spec: rules: - host: nginx.weave.pub http: paths: - backend: serviceName: nginx-static servicePort: 80
重新應用
kubectl apply -f nginx-static-ingress.yaml
3.4 總結
1、在實際應用場景,常常會把多個服務部署在不同的namespace,來達到隔離服務的目的,比如A服務部署在namespace-A,B服務部署在namespace-B。這種情況下,就需要聲明Ingress-A、Ingress-B兩個Ingress分別用於暴露A服務和B服務,且Ingress-A必須處於namespace-A,Ingress-B必須處於namespace-B。否則Controller無法正確解析Ingress的規則。
2、集群內可以聲明多個Ingress和多個Ingress Controller,一個Ingress Controller可以監聽多個Ingress,Ingress和其定義的服務必須處於同一namespace。
3、快速擴容,隨着業務流量不斷增長,集群規模不斷擴大,只需要簡單地通過打標的方式來快速擴容Ingress接入層;然后再把這幾個node節點加入到lb中,然后對應的域名解析到該lb即可實現ingress的高可用。
到這里ingress部署完成。
四、node增刪
4.1 增加node方法
4.1.1 基本設置
執行 1.3.4-1.3.6 步驟
4.1.2 配置kubelet組件
執行1.7.3~1.7.7,1.8.3-1.8.4,1.8.7,2.4后,還需操作如下:
復制matser上/opt/kubernetes/ssl/ca.pem,到node相同目錄
4.1.3 配置calico相關證書
復制matser上/opt/etcd/ssl/{ca.pem,server-key.pem,server.pem},到node相同目錄,並重命名node上的etcd證書名稱(calico網絡需要該證書)
cp ca.pem etcd-ca && cp server-key.pem etcd-key && cp server.pem etcd-cert
重啟kubelet組件
systemctl daemon-reload && systemctl restart kubelet && systemctl status kubelet
systemctl daemon-reload && systemctl restart kube-proxy && systemctl status kube-proxy
4.1.4 測試calico網絡正常
master節點新建測試文件
cat >> test-nginx.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: test-nginx spec: replicas: 1 selector: matchLabels: k8s-app: test-nginx template: metadata: labels: k8s-app: test-nginx spec: nodeSelector: kubernetes.io/hostname: "k8snode3" containers: - name: test-nginx image: nginx:1.9 ports: - containerPort: 80 EOF
#創建pod
kubectl create -f test-nginx.yaml
#創建服務
kubectl expose deploy test-nginx
#查看狀態
kubectl get svc,pod --all-namespaces -o wide
如果異常,查看日志
kubectl describe pod/test-nginx-747548b77d-8cs65
報錯: k8snode3 Failed create pod sandbox: rpc error: code = Unknown desc = [failed to set up sandbox container "360e03c13615b9ad0c1e6d9c7fca1b300311398c038ea6d6587d465fb956f250" network for pod "my-nginx-6ccc5d6cbd-q2v5w": NetworkPlugin cni failed to set up pod "my-nginx-6ccc5d6cbd-q2v5w_default" network: context deadline exceeded, failed to clean up sandbox container "360e03c13615b9ad0c1e6d9c7fca1b300311398c038ea6d6587d465fb956f250" network for pod "my-nginx-6ccc5d6cbd-q2v5w": NetworkPlugin cni failed to teardown pod "my-nginx-6ccc5d6cbd-q2v5w_default" network: context deadline exceeded]
解決:重啟該node節點可解決。
4.1.5 測試coredns正常
kubectl run curl --image=radial/busyboxplus:curl --restart=Never --rm -it
curl test-nginx.default
4.1.6 測試ingress正常
vim test-nginx-ingress.yaml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-checker-ingress annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-connect-timeout: "14400" nginx.ingress.kubernetes.io/proxy-send-timeout: "14400" nginx.ingress.kubernetes.io/proxy-read-timeout: "14400" spec: rules: - host: test-nginx.weave.pub http: paths: - backend: serviceName: test-nginx servicePort: 80
kubectl apply -f test-nginx-ingress.yaml
然后curl測試下
4.2 刪除node方法
kubectl get nodes
kubectl cordon k8s-node1 #設置不可調度
kubectl drain k8snode1 --ignore-daemonsets --delete-local-data #驅離pod到其他節點
kubectl get pod --all-namespaces -o wide |grep k8snode1 #查看是否還有pod
kubectl delete node k8snode1 #刪除節點
4.3 Node隔離與恢復
在硬件升級、硬件維護的情況下,我們需要將某些Node進行隔離,脫離k8s的調度范圍。k8s提供了一套機制,既可以將Node納入調度范圍,也可以將Node脫離調度范圍。
kubectl cordon k8s-node1 #將k8s-node1節點設置為不可調度模式
kubectl drain k8s-node1 #將當前運行在k8s-node1節點上的容器驅離
kubectl uncordon k8s-node1 #執行完維護后,將節點重新加入調度
4.4 刪除頑固namespace
檢查該namespace下是否還有資源:kubectl get all --namespace=ingress-nginx
刪除資源:kubectl delete pods <pod> --grace-period=0 --force
然后編輯namespace:kubectl edit ns ingress-nginx
注釋掉finalizers部分,保存即會刪除該ns
再次查看已被刪除:kubectl get ns