功能說明
- CNI 插件自動部署;
- Dashboard UI 自動部署;
- Metrics Server 自動部署;
- core DNS 自動部署;
- 一鍵加入新的 Node;
- Ingress-Controller 自動部署;
- 多 Master 高可用(Keepalived + Nginx)一鍵部署;
- 透明支持 CentOS 7 和 Ubuntu 16/18;
- 多版本兼容(已通過測試的版本有: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)絡插件可選部署(Flannel Or Calico);
- 支持容器運行時可選部署(Containerd Or Docker);
- 支持最新 Kubernetes 1.20.x 版本的一鍵部署;
版本
CentOS 7.6、7.8、Ubuntu 16.04 和 Ubuntu 18.04 上都是已經(jīng)測試OK,可以完全能夠一鍵跑完。
注意:假如你是使用 Ubuntu 系統(tǒng),需要先在所有節(jié)點上安裝 python 環(huán)境。因為 Ansible 依賴被控端的 python 環(huán)境,而 Ubuntu 系統(tǒng)默認是沒有的(CentOS 默認有),執(zhí)行 sudo apt install python-minimal 安裝即可
環(huá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為對應版本的 Kubernetes 二進制包,選擇一個你需要的版本即可,來源于官網(wǎng)未作任何修改,更多版本可點擊此鏈接自行選擇合適的版本;
下載好后它們上傳到服務器,并將 Kubernetes 二進制包移動到 packages 目錄下,我這里選擇的是 v1.19.3 版本的二進制包,所以最終 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 目錄放到服務器的 /opt 目錄下,所以最終 packages 目錄的絕對路徑為 /opt/packages ,這個路徑要和后面 hosts.yml 中的 package_dir 變量值設置的路徑對應
安裝 Ansible 和 Git
安裝 Ansible 和 Git,我這里使用的是 CentOS 7.8 做演示,直接使用 YUM 安裝即可:
$ yum install ansible git -y
如果使用的是 Ubuntu,那么此時不能直接使用 apt 來安裝 Ansible,因為默認的版本太低了,需要執(zhí)行下面的操作添加源來安裝新版本的 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)說明
目錄結(jié)構(gòu)如下:
$ unzip ansible-deploy-kubernetes-master.zip
$ ls ansible-deploy-kubernetes-master/
hosts.yml manifests README.md roles run.yml
下面對上述幾個文件做一下說明:
hosts.yml:主機清單以及配置;
manifests:存放 Kubernetes 使用的 manifests,如 CoreDNS、Flannel、Dashboard 等,后續(xù)所有使用到的 manifests 都將放在這里方便配置改動;
roles:標準的 Ansible 角色目錄;
run.yml:此 Ansible 的入口 Playbook;
配置說明
為讓部署操作簡單易懂,我將所有可能修改的配置都放到了 hosts.yml 文件中,下面對 hosts.yml 配置進行說明:
all:
vars:
# SSH 用戶名
ansible_user: root
# SSH 密碼
ansible_ssh_pass: root1234
# 用戶的 sudo 提權(quán)密碼
ansible_sudo_pass: root1234
# 標識是否是多 Master 架構(gòu)
is_mutil_master: yes
# 多 Master 架構(gòu)時會使用 Nginx 來四層代理多個 Master 中的 APIServer,Nginx 四層代理可能有多個,這多個代理之間使用 Keepalived 提供 VIP 進行高可用,該字段就是用來設置該 VIP
virtual_ip: 10.0.1.200
# Keepalived VIP 綁定的網(wǎng)卡,如果多個主機網(wǎng)卡名不同,則可定義在對應的主機變量下
virtual_ip_device: eth0
# Service 網(wǎng)絡網(wǎng)段,默認為 10.0.0.0/24
service_net: 10.0.0.0/24
# Pod 網(wǎng)絡網(wǎng)段,默認為 10.244.0.0/16
pod_net: 10.244.0.0/16
# 多主架構(gòu)時 Nginx 代理 APIServer 使用的端口,如果代理和 APIServer 在同一臺主機,則不可為 6443,因為 APIServer 的默認端口為 6443
proxy_master_port: 7443
# 應用的安裝目錄,kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy、nginx、cni、docker、keepalived 等這些應用程序的安裝目錄
install_dir: /opt/apps/
# 二進制包的存放目錄,就是上面的壓縮包 kubernetes-1.19.0-zze-ansible.bin.tar.gz 解壓到的目錄
package_dir: /opt/packages/
# 證書存放目錄,kubernetes 和 ETCD 的運行需要一些證書,這里先生成所有證書保存到這個目錄,然后從這里分發(fā)到各個需要對應證書的節(jié)點,要求當前運行 Ansible 的用戶擁有該目錄的寫權(quán)限,否則證書無法生成(或者使用 sudo 執(zhí)行 ansible-playbook)
tls_dir: /opt/k8s_tls
# 提供 NTP 時間同步服務的主機,將會添加到定時任務,因為考慮到可能會使用內(nèi)建的時間服務器,所以把這個地址提取了出來
ntp_host: ntp1.aliyun.com
# 是否可以連接到 internet,如果可以,則會自動裝 ntpdate 等工具,該字段暫時只有控制聯(lián)網(wǎng)安裝一些軟件的功能,主要預留為后續(xù)離線部署開關(guān)
have_network: yes
# 是否修改 yum 源或 apt 源為阿里云,支持 CentOS 7、Ubuntu 16、Ubuntu 18,注意,會清空原有的源配置
replace_repo: yes
# API Server 證書預留 IP 列表,默認情況下:
# - 單 master 只會添加 master 節(jié)點 IP 到證書;
# - 多 master 會添加 master 節(jié)點 IP 和 ha_proxy 節(jié)點 IP 到證書
# 所以這里可以放一些將來打算擴展作為 Master 的主機的 IP
api_server_ext_ip_list:
- 10.0.1.210
- 10.0.1.211
- 10.0.1.212
# 可信任的 Docker 鏡像倉庫地址,默認僅允許 HTTPS 倉庫,添加后可支持 HTTP,用于渲染 /opt/apps/docker/conf/daemon.json
docker_insecure_registries:
- 10.0.1.122
- 10.0.1.123
# Docker 鏡像倉庫加速地址,可選,注釋后默認為我的阿里云鏡像加速地址
docker_registry_mirrors: https://7hsct51i.mirror.aliyuncs.com
# kubelet 用來發(fā)送簽發(fā)證書請求用的 Token,可通過 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
kubelet_bootstrap_token: 8fba966b6e3b5d182960a30f6cb94428
# Kubernetes 使用的 pause 鏡像,無需解釋
pause_image: registry.cn-shenzhen.aliyuncs.com/zze/pause:3.2
# Dashboard Web UI 使用的端口 30000-32767 之間
dashboard_port: 30001
# 保存 Dashboard 訪問 Token 的文件名,在當前 hosts.yml 同級目錄下
dashboard_token_file: dashboard_token.txt
# 選擇 Ingress Controller 的類型,目前可選 nginx 和 haproxy,可使用在 hosts 節(jié)對應主機下添加 ingress: yes 標識僅在該主機上部署 Ingress-Controller,如果沒有標識則默認在所有 Node 上部署,注釋此變量則不會部署 Ingress Controller
ingress_controller_type: nginx
# 選擇 CNI 網(wǎng)絡插件的類型,目前可選 flannel 和 calico,calico 默認使用 BGP 模式,注釋此變量則不會部署 CNI 網(wǎng)絡插件
# Ansible部署二進制的k8s之calico網(wǎng)絡插件
# 地址:http://www.itdecent.cn/p/65fbd39d2d54
cni_type: flannel
# 選擇 kubelet 使用的容器運行時,先支持 docker 和 containerd,kubernetes 1.20+ 后推薦使用 containerd,即便設置 containerd 為容器運行時,為方便使用依舊會在所有 node 上部署 docker
container_runtime: containerd
# 下面為主機清單配置,只不過是 YAML 格式,每一個 IP 代表一個主機,其下級字段為對應的主機變量,即如下配置有三個主機
hosts:
10.0.1.201:
# 主機名,會自動設置對應節(jié)點的主機名為該屬性值,并且 Kubernetes 的節(jié)點名稱也會使用它
hostname: k8s-master1
# 標識當前節(jié)點是否是 Master 節(jié)點
master: yes
# 標識當前節(jié)點時 Node 節(jié)點
node: yes
# 標識當前節(jié)點是否是 ETCD 節(jié)點
etcd: yes
# 標識當前節(jié)點是否用作 API Server 的代理節(jié)點,如果啟用,將會在該節(jié)點上運行 Nginx 和 Keepalived(僅在多 Master 時生效)
proxy_master: yes
# 當前節(jié)點用作代理節(jié)點時會啟動一個 Keepalived,該字段用來指定 Keepalived 配置中的優(yōu)先級,優(yōu)先級越高,VIP 則越優(yōu)先綁定到該節(jié)點
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
從上述配置可以看出:
上述配置最終會創(chuàng)建一個三節(jié)點的雙 Master 三 Node 的 Kubernete 集群,并且每個節(jié)點也是 ETCD 集群中的一個成員;
10.0.1.201 和 10.0.1.202 作為 Master 的同時也會作為 API Server 的代理節(jié)點;
10.0.1.201 的優(yōu)先級(proxy_priority)比 10.0.1.202 高,所以最終 Keepalived 管理的 VIP 會優(yōu)先綁定到 10.0.1.201 上;
開始部署
按需修改 hosts.yml,大部分配置保持默認即可,幾乎僅需要修改節(jié)點 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í)行下面命令開始部署操作:
$ 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 到當前 ansible 目錄] ***************************************************************************************************************************************************
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é)點
要添加 Node 節(jié)點也很簡單,僅需在 hosts.yml 下新添加一個節(jié)點,并添加一個主機變量 node: yes 標識它為 Node 節(jié)點,我這里要添加一個 10.0.1.204 的主機為新 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 時限定僅執(zhí)行新 Node 節(jié)點相關(guān)的 Task,如下:
$ sudo ansible-playbook -i hosts.yml run.yml --limit 10.0.1.204
如果需要同時添加多個 Node 節(jié)點,有如下兩種方法:
1)使用 --limit 時后面指定多個 Node IP,以逗號 , 分隔;
2)可以將多個 Node 節(jié)點的 IP 保存到一個文本文件,每行一個 IP,然后執(zhí)行 ansible-playbook 時使用 --limit @<文件名> 即可;
執(zhí)行完成后在 Master 節(jié)點可以接收到新 Node 中的 Kubulet 發(fā)出的證書申請:
$ kubectl get csr | grep Pending
node-csr-jHEi1_yP3TNX80M8_4KPRxIziC7E-bkf07rJpa_l4Vw 2m16s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending
直接在 Master 節(jié)點執(zhí)行下面命令允許簽發(fā)證書即可:
$ 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é)點了:
$ 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é)點(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)絡插件
檢查網(wǎng)絡插件是否正常,即檢查 Pod 能否跨主機通信,創(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
隨便進入一個 Pod 中的容器,ping 另外兩個主機上的 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