功能說(shuō)明
- CNI 插件自動(dòng)部署开睡;
- Dashboard UI 自動(dòng)部署;
- Metrics Server 自動(dòng)部署;
- core DNS 自動(dòng)部署芥挣;
- 一鍵加入新的 Node;
- Ingress-Controller 自動(dòng)部署耻台;
- 多 Master 高可用(Keepalived + Nginx)一鍵部署空免;
- 透明支持 CentOS 7 和 Ubuntu 16/18;
- 多版本兼容(已通過(guò)測(cè)試的版本有:v1.17.x盆耽、v1.18.x蹋砚、v1.19.x、v1.20.x)摄杂;
- 支持自定義 Service 和 Pod 網(wǎng)段坝咐;
- 支持 HAProxy Ingress Controller 和 Nginx Ingress Controller 可選部署;
- 支持 CNI 網(wǎng)絡(luò)插件可選部署(Flannel Or Calico)析恢;
- 支持容器運(yùn)行時(shí)可選部署(Containerd Or Docker)墨坚;
- 支持最新 Kubernetes 1.20.x 版本的一鍵部署;
版本
CentOS 7.6映挂、7.8泽篮、Ubuntu 16.04 和 Ubuntu 18.04 上都是已經(jīng)測(cè)試OK,可以完全能夠一鍵跑完柑船。
注意:假如你是使用 Ubuntu 系統(tǒng)帽撑,需要先在所有節(jié)點(diǎn)上安裝 python 環(huán)境。因?yàn)?Ansible 依賴被控端的 python 環(huán)境鞍时,而 Ubuntu 系統(tǒng)默認(rèn)是沒(méi)有的(CentOS 默認(rèn)有)亏拉,執(zhí)行 sudo apt install python-minimal
安裝即可
環(huán)境準(zhǔn)備
離線二進(jìn)制包下載
鏈接: https://pan.baidu.com/s/1uu1P8US6QlHynMGAWJhrUA
提取碼: p4j8
該鏈接提供的下載目錄結(jié)構(gòu)如下:
├── ansible-deploy-kubernetes-master.zip
├── kubernetes-server-linux-amd64-v1.17.13.tar.gz
├── kubernetes-server-linux-amd64-v1.18.10.tar.gz
├── kubernetes-server-linux-amd64-v1.19.3.tar.gz
├── kubernetes-server-linux-amd64-v1.20.5.tar.gz
└── packages
├── cfssl
│ ├── cfssl-certinfo_linux-amd64
│ ├── cfssljson_linux-amd64
│ └── cfssl_linux-amd64
├── cni-plugins-linux-amd64-v0.8.7.tgz
├── docker-19.03.9.tgz
└── etcd-v3.4.13-linux-amd64.tar.gz
要下載的文件:
packages
目錄下都是構(gòu)建 Kubernetes 集群必需的組件和工具历恐,直接下載該目錄;kubernetes-server-linux-amd64-v*.tar.gz
為對(duì)應(yīng)版本的 Kubernetes 二進(jìn)制包专筷,選擇一個(gè)你需要的版本即可弱贼,來(lái)源于官網(wǎng)未作任何修改,更多版本可點(diǎn)擊此鏈接自行選擇合適的版本磷蛹;
下載好后它們上傳到服務(wù)器吮旅,并將 Kubernetes 二進(jìn)制包移動(dòng)到 packages 目錄下,我這里選擇的是 v1.19.3 版本的二進(jìn)制包味咳,所以最終 packages 的目錄結(jié)構(gòu)如下:
$ tree packages/
packages/
├── cfssl
│ ├── cfssl-certinfo_linux-amd64
│ ├── cfssljson_linux-amd64
│ └── cfssl_linux-amd64
├── cni-plugins-linux-amd64-v0.8.7.tgz
├── containerd-1.4.4-linux-amd64.tar.gz
├── crictl-v1.20.0-linux-amd64.tar.gz
├── docker-19.03.9.tgz
├── etcd-v3.4.13-linux-amd64.tar.gz
└── kubernetes-server-linux-amd64-v1.20.5.tar.gz
將 packages 目錄放到服務(wù)器的 /opt 目錄下庇勃,所以最終 packages 目錄的絕對(duì)路徑為 /opt/packages ,這個(gè)路徑要和后面 hosts.yml 中的 package_dir 變量值設(shè)置的路徑對(duì)應(yīng)
安裝 Ansible 和 Git
安裝 Ansible
和 Git
槽驶,我這里使用的是 CentOS 7.8
做演示责嚷,直接使用 YUM 安裝即可:
$ yum install ansible git -y
如果使用的是 Ubuntu
,那么此時(shí)不能直接使用 apt
來(lái)安裝 Ansible
掂铐,因?yàn)槟J(rèn)的版本太低了罕拂,需要執(zhí)行下面的操作添加源來(lái)安裝新版本的 Ansible
:
$ sudo apt update
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository --yes ppa:ansible/ansible:2.7.6
$ sudo apt update
$ sudo apt-get install ansible
取消 Ansible 檢查 Key:
$ vim /etc/ansible/ansible.cfg
# 取消此行注釋
host_key_checking = False
結(jié)構(gòu)說(shuō)明
目錄結(jié)構(gòu)如下:
$ unzip ansible-deploy-kubernetes-master.zip
$ ls ansible-deploy-kubernetes-master/
hosts.yml manifests README.md roles run.yml
下面對(duì)上述幾個(gè)文件做一下說(shuō)明:
hosts.yml:主機(jī)清單以及配置;
manifests:存放 Kubernetes 使用的 manifests全陨,如 CoreDNS爆班、Flannel、Dashboard 等辱姨,后續(xù)所有使用到的 manifests 都將放在這里方便配置改動(dòng)柿菩;
roles:標(biāo)準(zhǔn)的 Ansible 角色目錄;
run.yml:此 Ansible 的入口 Playbook雨涛;
配置說(shuō)明
為讓部署操作簡(jiǎn)單易懂枢舶,我將所有可能修改的配置都放到了 hosts.yml
文件中,下面對(duì) hosts.yml
配置進(jìn)行說(shuō)明:
all:
vars:
# SSH 用戶名
ansible_user: root
# SSH 密碼
ansible_ssh_pass: root1234
# 用戶的 sudo 提權(quán)密碼
ansible_sudo_pass: root1234
# 標(biāo)識(shí)是否是多 Master 架構(gòu)
is_mutil_master: yes
# 多 Master 架構(gòu)時(shí)會(huì)使用 Nginx 來(lái)四層代理多個(gè) Master 中的 APIServer替久,Nginx 四層代理可能有多個(gè)凉泄,這多個(gè)代理之間使用 Keepalived 提供 VIP 進(jìn)行高可用,該字段就是用來(lái)設(shè)置該 VIP
virtual_ip: 10.0.1.200
# Keepalived VIP 綁定的網(wǎng)卡侣肄,如果多個(gè)主機(jī)網(wǎng)卡名不同旧困,則可定義在對(duì)應(yīng)的主機(jī)變量下
virtual_ip_device: eth0
# Service 網(wǎng)絡(luò)網(wǎng)段,默認(rèn)為 10.0.0.0/24
service_net: 10.0.0.0/24
# Pod 網(wǎng)絡(luò)網(wǎng)段稼锅,默認(rèn)為 10.244.0.0/16
pod_net: 10.244.0.0/16
# 多主架構(gòu)時(shí) Nginx 代理 APIServer 使用的端口吼具,如果代理和 APIServer 在同一臺(tái)主機(jī),則不可為 6443矩距,因?yàn)?APIServer 的默認(rèn)端口為 6443
proxy_master_port: 7443
# 應(yīng)用的安裝目錄拗盒,kube-apiserver、kube-controller-manager锥债、kube-scheduler陡蝇、kubelet痊臭、kube-proxy、nginx登夫、cni广匙、docker、keepalived 等這些應(yīng)用程序的安裝目錄
install_dir: /opt/apps/
# 二進(jìn)制包的存放目錄恼策,就是上面的壓縮包 kubernetes-1.19.0-zze-ansible.bin.tar.gz 解壓到的目錄
package_dir: /opt/packages/
# 證書(shū)存放目錄鸦致,kubernetes 和 ETCD 的運(yùn)行需要一些證書(shū),這里先生成所有證書(shū)保存到這個(gè)目錄涣楷,然后從這里分發(fā)到各個(gè)需要對(duì)應(yīng)證書(shū)的節(jié)點(diǎn)分唾,要求當(dāng)前運(yùn)行 Ansible 的用戶擁有該目錄的寫(xiě)權(quán)限,否則證書(shū)無(wú)法生成(或者使用 sudo 執(zhí)行 ansible-playbook)
tls_dir: /opt/k8s_tls
# 提供 NTP 時(shí)間同步服務(wù)的主機(jī)狮斗,將會(huì)添加到定時(shí)任務(wù)绽乔,因?yàn)榭紤]到可能會(huì)使用內(nèi)建的時(shí)間服務(wù)器,所以把這個(gè)地址提取了出來(lái)
ntp_host: ntp1.aliyun.com
# 是否可以連接到 internet碳褒,如果可以折砸,則會(huì)自動(dòng)裝 ntpdate 等工具,該字段暫時(shí)只有控制聯(lián)網(wǎng)安裝一些軟件的功能骤视,主要預(yù)留為后續(xù)離線部署開(kāi)關(guān)
have_network: yes
# 是否修改 yum 源或 apt 源為阿里云鞍爱,支持 CentOS 7、Ubuntu 16专酗、Ubuntu 18,注意盗扇,會(huì)清空原有的源配置
replace_repo: yes
# API Server 證書(shū)預(yù)留 IP 列表祷肯,默認(rèn)情況下:
# - 單 master 只會(huì)添加 master 節(jié)點(diǎn) IP 到證書(shū);
# - 多 master 會(huì)添加 master 節(jié)點(diǎn) IP 和 ha_proxy 節(jié)點(diǎn) IP 到證書(shū)
# 所以這里可以放一些將來(lái)打算擴(kuò)展作為 Master 的主機(jī)的 IP
api_server_ext_ip_list:
- 10.0.1.210
- 10.0.1.211
- 10.0.1.212
# 可信任的 Docker 鏡像倉(cāng)庫(kù)地址疗隶,默認(rèn)僅允許 HTTPS 倉(cāng)庫(kù)佑笋,添加后可支持 HTTP,用于渲染 /opt/apps/docker/conf/daemon.json
docker_insecure_registries:
- 10.0.1.122
- 10.0.1.123
# Docker 鏡像倉(cāng)庫(kù)加速地址斑鼻,可選蒋纬,注釋后默認(rèn)為我的阿里云鏡像加速地址
docker_registry_mirrors: https://7hsct51i.mirror.aliyuncs.com
# kubelet 用來(lái)發(fā)送簽發(fā)證書(shū)請(qǐng)求用的 Token,可通過(guò) head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
kubelet_bootstrap_token: 8fba966b6e3b5d182960a30f6cb94428
# Kubernetes 使用的 pause 鏡像坚弱,無(wú)需解釋
pause_image: registry.cn-shenzhen.aliyuncs.com/zze/pause:3.2
# Dashboard Web UI 使用的端口 30000-32767 之間
dashboard_port: 30001
# 保存 Dashboard 訪問(wèn) Token 的文件名蜀备,在當(dāng)前 hosts.yml 同級(jí)目錄下
dashboard_token_file: dashboard_token.txt
# 選擇 Ingress Controller 的類型,目前可選 nginx 和 haproxy荒叶,可使用在 hosts 節(jié)對(duì)應(yīng)主機(jī)下添加 ingress: yes 標(biāo)識(shí)僅在該主機(jī)上部署 Ingress-Controller碾阁,如果沒(méi)有標(biāo)識(shí)則默認(rèn)在所有 Node 上部署,注釋此變量則不會(huì)部署 Ingress Controller
ingress_controller_type: nginx
# 選擇 CNI 網(wǎng)絡(luò)插件的類型些楣,目前可選 flannel 和 calico脂凶,calico 默認(rèn)使用 BGP 模式宪睹,注釋此變量則不會(huì)部署 CNI 網(wǎng)絡(luò)插件
# Ansible部署二進(jìn)制的k8s之calico網(wǎng)絡(luò)插件
# 地址:http://www.reibang.com/p/65fbd39d2d54
cni_type: flannel
# 選擇 kubelet 使用的容器運(yùn)行時(shí),先支持 docker 和 containerd蚕钦,kubernetes 1.20+ 后推薦使用 containerd亭病,即便設(shè)置 containerd 為容器運(yùn)行時(shí),為方便使用依舊會(huì)在所有 node 上部署 docker
container_runtime: containerd
# 下面為主機(jī)清單配置嘶居,只不過(guò)是 YAML 格式罪帖,每一個(gè) IP 代表一個(gè)主機(jī),其下級(jí)字段為對(duì)應(yīng)的主機(jī)變量食听,即如下配置有三個(gè)主機(jī)
hosts:
10.0.1.201:
# 主機(jī)名胸蛛,會(huì)自動(dòng)設(shè)置對(duì)應(yīng)節(jié)點(diǎn)的主機(jī)名為該屬性值,并且 Kubernetes 的節(jié)點(diǎn)名稱也會(huì)使用它
hostname: k8s-master1
# 標(biāo)識(shí)當(dāng)前節(jié)點(diǎn)是否是 Master 節(jié)點(diǎn)
master: yes
# 標(biāo)識(shí)當(dāng)前節(jié)點(diǎn)時(shí) Node 節(jié)點(diǎn)
node: yes
# 標(biāo)識(shí)當(dāng)前節(jié)點(diǎn)是否是 ETCD 節(jié)點(diǎn)
etcd: yes
# 標(biāo)識(shí)當(dāng)前節(jié)點(diǎn)是否用作 API Server 的代理節(jié)點(diǎn)樱报,如果啟用葬项,將會(huì)在該節(jié)點(diǎn)上運(yùn)行 Nginx 和 Keepalived(僅在多 Master 時(shí)生效)
proxy_master: yes
# 當(dāng)前節(jié)點(diǎn)用作代理節(jié)點(diǎn)時(shí)會(huì)啟動(dòng)一個(gè) Keepalived,該字段用來(lái)指定 Keepalived 配置中的優(yōu)先級(jí)迹蛤,優(yōu)先級(jí)越高民珍,VIP 則越優(yōu)先綁定到該節(jié)點(diǎn)
proxy_priority: 110
10.0.1.202:
hostname: k8s-master2
node: yes
master: yes
etcd: yes
proxy_master: yes
proxy_priority: 100
10.0.1.203:
hostname: k8s-node1
etcd: yes
node: yes
ingress: yes
從上述配置可以看出:
上述配置最終會(huì)創(chuàng)建一個(gè)三節(jié)點(diǎn)的雙 Master 三 Node 的 Kubernete 集群,并且每個(gè)節(jié)點(diǎn)也是 ETCD 集群中的一個(gè)成員盗飒;
10.0.1.201 和 10.0.1.202 作為 Master 的同時(shí)也會(huì)作為 API Server 的代理節(jié)點(diǎn)嚷量;
10.0.1.201 的優(yōu)先級(jí)(proxy_priority)比 10.0.1.202 高,所以最終 Keepalived 管理的 VIP 會(huì)優(yōu)先綁定到 10.0.1.201 上逆趣;
開(kāi)始部署
按需修改 hosts.yml蝶溶,大部分配置保持默認(rèn)即可,幾乎僅需要修改節(jié)點(diǎn) IP 和密碼宣渗,我這里修改完配置之后 hosts.yml 內(nèi)容如下:
all:
vars:
ansible_user: root
ansible_ssh_pass: root1234
ansible_sudo_pass: root1234
is_mutil_master: yes
virtual_ip: 10.0.1.200
virtual_ip_device: eth0
proxy_master_port: 7443
install_dir: /opt/apps/
package_dir: /opt/packages/
tls_dir: /opt/k8s_tls
ntp_host: ntp1.aliyun.com
have_network: yes
replace_repo: yes
docker_registry_mirrors: https://7hsct51i.mirror.aliyuncs.com
kubelet_bootstrap_token: 8fba966b6e3b5d182960a30f6cb94428
pause_image: registry.cn-shenzhen.aliyuncs.com/zze/pause:3.2
dashboard_port: 30001
dashboard_token_file: dashboard_token.txt
ingress_controller_type: haproxy
cni_type: flannel
hosts:
10.0.1.201:
hostname: k8s-master1
master: yes
node: yes
etcd: yes
proxy_master: yes
proxy_priority: 110
10.0.1.202:
hostname: k8s-master2
master: yes
node: yes
etcd: yes
proxy_master: yes
proxy_priority: 100
10.0.1.203:
hostname: k8s-node1
etcd: yes
node: yes
ingress: yes
修改完成后執(zhí)行下面命令開(kāi)始部署操作:
$ sudo ansible-playbook -i hosts.yml run.yml
...
TASK [deploy_manifests : 打印 token 信息] ***************************************************************************************************************************************************************
ok: [10.0.1.201] => {
"msg": "token: eyJhbGciOiJSUzI1NiIsImtpZCI6IlVnU2Z6aTM1a0I1S3J5T04yVmMwQTNoWC0xZnF2RThybXBzQU9pcWhUYnMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tamdzZHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMWI3YzcxMWYtMGQwYi00MTJjLTkwMGEtMzY5ZmVmZGZiMzZjIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.oxjPtZhyOylFO8mvWBJ6E8UD42161-jxLMXYeJuQSPKs_wioUqR2Fkx3p7DeYb3b0A4_I4cT0APC1nM1tQnuah9UH9wb6hryzdoiH8WVfNZjjGJcPCC59hMOLFfBswQOo5f9zIbZnMdDjo9NXo96RQrxlu_JxQM_l3UYpr2Gn5CRwZrMVQBRQ5mhDd2yTK-wF-I0rcwoIDAUGt-ajFRZ7J9V4AHxXjHDfA0XqVCay25ZKiJ50UkkGV0PCwU7VwZzdNqF-nOxRkhDnX7w13LVxlwaWvpBMcHimX2HU0P6orufslKlVrQAdj3nenZ4dKPW0Ss1ndK0nRUpOuOgd4hi7g"
}
skipping: [10.0.1.202]
skipping: [10.0.1.203]
TASK [deploy_manifests : 保存 token 到當(dāng)前 ansible 目錄](méi) ***************************************************************************************************************************************************
skipping: [10.0.1.202]
skipping: [10.0.1.203]
changed: [10.0.1.201]
PLAY RECAP ******************************************************************************************************************************************************************************************
10.0.1.201 : ok=117 changed=82 unreachable=0 failed=0 skipped=19 rescued=0 ignored=0
10.0.1.202 : ok=69 changed=53 unreachable=0 failed=0 skipped=33 rescued=0 ignored=0
10.0.1.203 : ok=49 changed=39 unreachable=0 failed=0 skipped=53 rescued=0 ignored=0
添加 Node 節(jié)點(diǎn)
要添加 Node
節(jié)點(diǎn)也很簡(jiǎn)單抖所,僅需在 hosts.yml
下新添加一個(gè)節(jié)點(diǎn),并添加一個(gè)主機(jī)變量 node: yes
標(biāo)識(shí)它為 Node
節(jié)點(diǎn)痕囱,我這里要添加一個(gè) 10.0.1.204
的主機(jī)為新 Node
田轧,所以在 hosts.yml
中添加配置如下:
all:
vars:
ansible_user: root
ansible_ssh_pass: root1234
ansible_sudo_pass: root1234
...
hosts:
...
10.0.1.203:
hostname: k8s-node1
etcd: yes
node: yes
10.0.1.204:
hostname: k8s-node2
node: yes
然后執(zhí)行 Playbook 時(shí)限定僅執(zhí)行新 Node 節(jié)點(diǎn)相關(guān)的 Task,如下:
$ sudo ansible-playbook -i hosts.yml run.yml --limit 10.0.1.204
如果需要同時(shí)添加多個(gè) Node 節(jié)點(diǎn)鞍恢,有如下兩種方法:
1)使用 --limit 時(shí)后面指定多個(gè) Node IP
傻粘,以逗號(hào) , 分隔;
2)可以將多個(gè) Node
節(jié)點(diǎn)的 IP 保存到一個(gè)文本文件帮掉,每行一個(gè) IP弦悉,然后執(zhí)行 ansible-playbook
時(shí)使用 --limit @<文件名>
即可;
執(zhí)行完成后在 Master 節(jié)點(diǎn)可以接收到新 Node
中的 Kubulet
發(fā)出的證書(shū)申請(qǐng):
$ kubectl get csr | grep Pending
node-csr-jHEi1_yP3TNX80M8_4KPRxIziC7E-bkf07rJpa_l4Vw 2m16s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending
直接在 Master
節(jié)點(diǎn)執(zhí)行下面命令允許簽發(fā)證書(shū)即可:
$ kubectl get csr | awk '$NF=="Pending"{print $1}' | xargs -i kubectl certificate approve {}
certificatesigningrequest.certificates.k8s.io/node-csr-jHEi1_yP3TNX80M8_4KPRxIziC7E-bkf07rJpa_l4Vw approved
然后就可以查看到新加入的節(jié)點(diǎn)了:
$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready <none> 26m v1.20.5
k8s-master2 Ready <none> 21m v1.20.5
k8s-node1 Ready <none> 26m v1.20.5
k8s-node2 NotReady <none> 22s v1.20.5
檢查
檢查 Node
在 Master 節(jié)點(diǎn)(10.0.1.201 或 10.0.1.202)上檢查 Node 是否正常:
$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready <none> 113s v1.20.5
k8s-master2 Ready <none> 113s v1.20.5
k8s-node1 Ready <none> 113s v1.20.5
檢查 CNI 網(wǎng)絡(luò)插件
檢查網(wǎng)絡(luò)插件是否正常旭寿,即檢查 Pod 能否跨主機(jī)通信警绩,創(chuàng)建如下 Deployment 資源:
$ cat test_deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test
spec:
replicas: 3
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- image: busybox:latest
name: busybox
command: ["sleep", "3600"]
$ kubectl apply -f test_deploy.yml
deployment.apps/test created
隨便進(jìn)入一個(gè) Pod 中的容器,ping 另外兩個(gè)主機(jī)上的 Pod:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-54fdd84b68-j9zwq 1/1 Running 0 77s 10.244.0.2 k8s-node1 <none> <none>
test-54fdd84b68-w64jv 1/1 Running 0 77s 10.244.2.4 k8s-master1 <none> <none>
test-54fdd84b68-zptw8 1/1 Running 0 77s 10.244.1.3 k8s-master2 <none> <none>
$ kubectl exec -it test-54fdd84b68-j9zwq -- sh
/ # ping 10.244.2.4
PING 10.244.2.4 (10.244.2.4): 56 data bytes
64 bytes from 10.244.2.4: seq=0 ttl=62 time=1.334 ms
^C
--- 10.244.2.4 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.334/1.334/1.334 ms
/ #
/ # ping 10.244.1.3
PING 10.244.1.3 (10.244.1.3): 56 data bytes
64 bytes from 10.244.1.3: seq=0 ttl=62 time=0.761 ms