本文內容參考《kuberneters進階實戰》/馬哥的新書/推薦 部署前的準備 主機名稱解析 分散式系統環境中的多主機通信通常基於主機名稱進行,這在IP地址存在變化的可能性時為主機提供了固定的訪問入口,因此一般需要有專用的DNS服務負責解決各節點主機名。不過,考慮到此處部署的是測試集群,因此為了降低 ...
本文內容參考《kuberneters進階實戰》/馬哥的新書/推薦
部署前的準備
主機名稱解析
分散式系統環境中的多主機通信通常基於主機名稱進行,這在IP地址存在變化的可能性時為主機提供了固定的訪問入口,因此一般需要有專用的DNS服務負責解決各節點主機名。不過,考慮到此處部署的是測試集群,因此為了降低系統的複雜度,這裡將採用基於hosts的文件進行主機名稱解析
master節點和nodes都需要修改hosts文件
192.168.18.64 master
192.168.18.65 node1
192.168.18.66 node2
192.168.18.67 node3
主機時間同步
如果使用的是雲伺服器,一般雲廠商都已經設置好了
關閉防火牆
各Node運行的kube-proxy組件均要藉助iptables或ipvs構建Service資源對象,該資源對象是Kubernetes的核心資源之一。出於簡化問題複雜度之需,這裡需要事先關閉所有主機之上的iptables或firewalld服務
# systemctl stop iptables.service
# systemctl disable iptables.service
關閉並僅用SELinux
禁用swap設備 (可選)
kubeadm預設會預先檢查當前主機是否禁用了Swap設備,併在未禁用時強制終止部署過程。因此,在主機記憶體資源充裕的條件下,需要禁用所有的Swap設備。
# 關閉swap設備
swapoff -a
然後編輯/etc/fstab
配置文件,另外部署時也可以不禁用swap設備,可在使用kubeadm命令時額外使用相關命令忽略檢查錯誤
啟用ipvs內核模塊 (可選)
Kubernetes1.11之後的版本預設支持使用ipvs代理模式的Service資源,但它依賴於ipvs相關的內核模塊,而這些模塊預設不會自動載入。因此,這裡選擇創建載入內核模塊相關的腳本文件/etc/sysconfig/modules/ipvs.modules,設定於系統引導時自動載入的ipvs相關的內核模塊,以支持使用ipvs代理模式的Service資源。文件內容如下:
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for i in $(ls $ipvs_mods_dir | grep -o "^[^.] *"); do
/sbin/modinfo -F filename $i &> /dev/null
if [ $ -eq 0 ]; then
/sbin/ modprobe $i
fi
done
然後修改文件許可權,並手動為當前系統環境載入內核
chmod +x /etc/sysconfig/modules/ipvs.modules
/etc/sysconfig/modules/ipvs.modules
鏡像下載
為啥要將鏡像單獨準備,因為這個門檻越不過去,你會遇到很多莫名其妙的問題(對於新手來講)
以下是必須的鏡像和正在運行的docker容器
[root@master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s.gcr.io/kube-proxy v1.13.1 fdb321fd30a0 4 weeks ago 80.2MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-proxy-amd64 v1.13.1 fdb321fd30a0 4 weeks ago 80.2MB
k8s.gcr.io/kube-apiserver v1.13.1 40a63db91ef8 4 weeks ago 181MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-apiserver-amd64 v1.13.1 40a63db91ef8 4 weeks ago 181MB
k8s.gcr.io/kube-scheduler v1.13.1 ab81d7360408 4 weeks ago 79.6MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-scheduler-amd64 v1.13.1 ab81d7360408 4 weeks ago 79.6MB
k8s.gcr.io/kube-controller-manager v1.13.1 26e6f1db2a52 4 weeks ago 146MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-controller-manager-amd64 v1.13.1 26e6f1db2a52 4 weeks ago 146MB
k8s.gcr.io/coredns 1.2.6 f59dcacceff4 2 months ago 40MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/coredns 1.2.6 f59dcacceff4 2 months ago 40MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/etcd-amd64 3.2.24 3cab8e1b9802 3 months ago 220MB
k8s.gcr.io/etcd 3.2.24 3cab8e1b9802 3 months ago 220MB
quay.io/coreos/flannel v0.10.0-amd64 f0fad859c909 11 months ago 44.6MB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/flannel v0.10.0-amd64 f0fad859c909 11 months ago 44.6MB
k8s.gcr.io/pause 3.1 da86e6ba6ca1 12 months ago 742kB
registry.cn-hangzhou.aliyuncs.com/mmyk8s/pause 3.1 da86e6ba6ca1 12 months ago 742kB
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
36d09d27fd26 f59dcacceff4 "/coredns -conf /etc…" 8 hours ago Up 8 hours k8s_coredns_coredns-86c58d9df4-cm4pm_kube-system_6e51adc0-14c0-11e9-ac10-000c29bed493_0
05bb6e3b85e9 f59dcacceff4 "/coredns -conf /etc…" 8 hours ago Up 8 hours k8s_coredns_coredns-86c58d9df4-g2mf4_kube-system_6e50f388-14c0-11e9-ac10-000c29bed493_0
51b284840974 k8s.gcr.io/pause:3.1 "/pause" 8 hours ago Up 8 hours k8s_POD_coredns-86c58d9df4-cm4pm_kube-system_6e51adc0-14c0-11e9-ac10-000c29bed493_0
b3e5b80bb640 k8s.gcr.io/pause:3.1 "/pause" 8 hours ago Up 8 hours k8s_POD_coredns-86c58d9df4-g2mf4_kube-system_6e50f388-14c0-11e9-ac10-000c29bed493_0
5f50cad2717e f0fad859c909 "/opt/bin/flanneld -…" 8 hours ago Up 8 hours k8s_kube-flannel_kube-flannel-ds-amd64-7xh79_kube-system_ad897b0d-14c0-11e9-ac10-000c29bed493_0
73bb596c654e 3cab8e1b9802 "etcd --advertise-cl…" 23 hours ago Up 23 hours k8s_etcd_etcd-master_kube-system_54caa73c3a366810eb1982ce52213834_1
d5d71dfc331c ab81d7360408 "kube-scheduler --ad…" 23 hours ago Up 23 hours k8s_kube-scheduler_kube-scheduler-master_kube-system_44b569a35761491825f4e7253fbf0543_1
7ff702474352 40a63db91ef8 "kube-apiserver --au…" 23 hours ago Up 23 hours k8s_kube-apiserver_kube-apiserver-master_kube-system_4e3289b38af39fb55c00956ffb875c26_1
590cb4078099 26e6f1db2a52 "kube-controller-man…" 23 hours ago Up 23 hours k8s_kube-controller-manager_kube-controller-manager-master_kube-system_7d0a1ff3545bbc890a67b0d02dc0f191_1
c22bcc9f6903 fdb321fd30a0 "/usr/local/bin/kube…" 23 hours ago Up 23 hours k8s_kube-proxy_kube-proxy-m8wsf_kube-system_b8572ad6-14bf-11e9-ac10-000c29bed493_1
8d63b75de565 k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_kube-flannel-ds-amd64-7xh79_kube-system_ad897b0d-14c0-11e9-ac10-000c29bed493_1
fe0b44fe8c09 k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_kube-proxy-m8wsf_kube-system_b8572ad6-14bf-11e9-ac10-000c29bed493_1
729321ce5699 k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_kube-scheduler-master_kube-system_44b569a35761491825f4e7253fbf0543_1
b635e5dd38d0 k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_etcd-master_kube-system_54caa73c3a366810eb1982ce52213834_1
85502af97ba9 k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_kube-apiserver-master_kube-system_4e3289b38af39fb55c00956ffb875c26_2
240c427dc4dc k8s.gcr.io/pause:3.1 "/pause" 23 hours ago Up 23 hours k8s_POD_kube-controller-manager-master_kube-system_7d0a1ff3545bbc890a67b0d02dc0f191_1
在後面初始化kuberneters集群的時候,依賴的這些鏡像預設是從k8s.gcr.io去pull鏡像,但是在國內是無法訪問的
我們可以通過阿裡雲或者騰訊雲先將鏡像構建在阿裡的鏡像倉庫中,然後再tag為需要的鏡像標簽
阿裡雲上自定義鏡像倉庫
倉庫中自定義的構建信息,這裡指定了dockerfile文件的地址在github上
這裡為github上dockerfile的內容,以官方鏡像為基礎鏡像構建後存在阿裡的鏡像倉庫中
所有鏡像構建完成後,通過命令pull到本地,打tag即可使用
寫了一個腳本,避免重覆的工作
#!/bin/bash
set -e
IMAGE_URL=registry.cn-hangzhou.aliyuncs.com/
IMAGE_URL_TAG=k8s.gcr.io
# 這裡為個人的阿裡雲鏡像倉庫賬戶
USER=
PASSWD=
REGNAME=
docker login $IMAGE_URL -u $USER -p $PASSWD
# 初始化集群需要的鏡像
#IMAGE_LIST=(coredns:1.2.6 etcd-amd64:3.2.24 kube-apiserver-amd64:v1.13.1 kube-controller-manager-amd64:v1.13.1 kube-proxy-amd64:v1.13.1 kube-scheduler-amd64:v1.13.1 pause:3.1)
for i in coredns:1.2.6 etcd-amd64:3.2.24 kube-apiserver-amd64:v1.13.1 kube-controller-manager-amd64:v1.13.1 kube-proxy-amd64:v1.13.1 kube-scheduler-amd64:v1.13.1 pause:3.1
do
docker pull $IMAGE_URL$REGNAME/$i
echo "$i下載成功"
done
# flannel插件鏡像
docker pull registry.cn-hangzhou.aliyuncs.com/mmyk8s/flannel:v0.10.0-amd64
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-proxy-amd64:v1.13.1 k8s.gcr.io/kube-proxy:v1.13.1
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-apiserver-amd64:v1.13.1 k8s.gcr.io/kube-apiserver:v1.13.1
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-controller-manager-amd64:v1.13.1 k8s.gcr.io/kube-controller-manager:v1.13.1
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-scheduler-amd64:v1.13.1 k8s.gcr.io/kube-scheduler:v1.13.1
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/kube-scheduler-amd64:v1.13.1 k8s.gcr.io/kube-scheduler:v1.13.1
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/coredns:1.2.6 k8s.gcr.io/coredns:1.2.6
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/etcd-amd64:3.2.24 k8s.gcr.io/etcd:3.2.24
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/flannel:v0.10.0-amd64 quay.io/coreos/flannel:v0.10.0-amd64
docker tag registry.cn-hangzhou.aliyuncs.com/mmyk8s/pause:3.1 k8s.gcr.io/pause:3.1
echo “標簽修改成功”
每個節點都需要這些鏡像!
還有一種方法沒用實踐過,在下文中初始化集群使用的是第一種方式,在第二種方式中,imageRepository: k8s.gcr.io
指定了鏡像倉庫地址,是否可以改為國內地址或者自己的私有倉庫地址,這樣就不用tag了。
部署kuberneters集群
kubeadm是用於快速構建Kubernetes集群的工具,隨著Kubernetes的發行版本而提供,使用它構建集群時,大致可分為如下幾步:
- 在Master及各Node安裝Docker、kubelet及kubeadm,並以系統守護進程的方式啟動Docker和kubelet服務。
- 在Master節點上通過kubeadminit命令進行集群初始化。
- 各Node通過kubeadmjoin命令加入初始化完成的集群中。
- 在集群上部署網路附件,如flannel或Calico等以提供Service網路及Pod網路。
為了簡化部署過程,kubeadm使用一組固定的目錄及文件路徑存儲相關的配置及數據文件,其中/etc/kubernetes目錄是所有文件或目錄的統一存儲目錄。它使用/etc/kubernetes/manifests目錄存儲各靜態Pod資源的配置清單,用到的文件有etcd.yaml、kube-apiserver.yaml、kube-controller-manager.yaml和kube-scheduler.yaml四個,它們的作用基本能夠見名知義。另外,/etc/kubernetes/目錄中還會為Kubernetes的多個組件存儲專用的kubeconfig文件,如kubelet.conf、controller-manager.conf、scheduler.conf和admin.conf等,它們分別為相關的組件提供接入APIServer的認證信息等。此外,它還會在/etc/kubernetes/pki目錄中存儲若幹私鑰和證書文件
設定容器運行的環境
這裡基本就是docker的安裝和一些簡單的配置
安裝kubelet和kubeadm
kubelet是運行於集群中每個節點之上的Kubernetes代理程式,它的核心功能在於通過APIServer獲取調度至自身運行的Pod資源的PodSpec並依之運行Pod對象。事實上,以自托管方式部署的Kubernetes集群,除了kubelet和Docker之外的所有組件均以Pod對象的形式運行
設定用於安裝kubelet、kubeadm和kubectl等組件的yum倉庫,編輯配置文件/etc/yum.repos.d/kubernetes.repo
kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
yum install kubelet kubeadm kubectl
配置kubelet
Kubernetes自1.8版本起強制要求關閉系統上的交換分區(Swap),否則kubelet將無法啟動。當然,用戶也可以通過將kubelet的啟動參數“--fail-swap-on”設置為“false”忽略此限制,尤其是系統上運行有其他重要進程且系統記憶體資源稍嫌不足時建議保留交換分區。
編輯kubelet的配置文件/etc/sysconfig/kubelet,設置其配置參數如下,以忽略禁止使用Swap的限制:
KUBELET_ EXTRA_ ARGS="--fail-swap-on=false"
待配置文件修改完成後,需要設定kubelet服務開機自動啟動,這也是kubeadm的強制要求:
systemctl enable kubelet.service
以上部分的配置需要在集群所有機器配置,install kubelet kubeadm kubectl是安裝集群的基本條件,這些服務的安裝使用基於docker,環境的配置,例如防火牆等是保證初始化集群等的最基本條件
master節點初始化集群
在Master節點上執行“kubeadminit”命令進行集群初始化。kubeadminit命令支持兩種初始化方式,一是通過命令行選項傳遞關鍵的參數設定,另一個是基於yaml格式的專用配置文件設定更詳細的配置參數
第一種方式:
kubeadm init --kubernetes-version=v1.13.1 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --apiserver-advertise-address=0.0.0.0 --ignore-preflight-errors=Swap
--kubernetes-version:正在使用的Kubernetes程式組件的版本號,需要與kubelet的版本號相同。
--pod-network-cidr:Pod網路的地址範圍,其值為CIDR格式的網路地址;使用flannel網路插件時,其預設地址為10.244.0.0/16。
--service-cidr:Service的網路地址範圍,其值為CIDR格式的網路地址,預設地址為10.96.0.0/12。
--apiserver-advertise-address:APIserver通告給其他組件的IP地址,一般應該為Master節點的IP地址,0.0.0.0表示節點上所有可用的地址。
--ignore-preflight-errors:忽略哪些運行時的錯誤信息,其值為Swap時,表示忽略因swap未關閉而導致的錯誤。
第二種方式:
kubeadminit也配置文件載入配置,以定製更豐富的部署選項。以下是符合前述命令設定方式的使用示例,不過,它明確定義了kubeProxy的模式為ipvs,並支持通過修改imageRepository的值來修改獲取系統鏡像時使用的鏡像倉庫。
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.13.1
api:
advertiseAddress: 192.168.18.64
bindPort: 6443
controlPlaneEndpoint: ""
imageRepository: k8s.gcr.io
kubeProxy:
config:
mode: "ipvs"
ipvs:
ExcludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kubeletConfiguration:
baseConfig:
cgroupDriver: cgroupfs
clusterDNS:
-10.96.0.10
clusterDomain: cluster.local
failSwapOn: false
resolvConf: /etc/resolv.conf
staticPodPath: /etc/kubernetes/manifests
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
將以上配置保存為kubedm-config.yaml
kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap
成功後會生成node節點加入集群的命令
kubeadm join 192.168.18.64:6443 --token 4mvox7.5l6fgyyqo761yxyf --discovery-token-ca-cert-hash sha256:1cd687ae5837b85a48f9ca93873aa67b30d29b1584db3b1f2ede946506735035
完成集群部署還需要執行三類操作:設定kubectl的配置文件、部署網路附件以及將各Node加入集群。下麵就來講解如何進行這三步操作。
設定kubectl的配置文件根據輸出的命令執行就可以
至此為止,一個KubernetesMaster節點已經基本配置完成。接下來即可通過APIServer來驗證其各組件的運行是否正常。kubectl有著眾多子命令,其中“getcompontsstatuses”即能顯示出集群組件當前的狀態,也可使用其簡寫格式“get cs”:
[root@master ~]# kubectl get cs
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}
若上面命令結果的STATUS欄位為“Healthy”,則表示組件處於健康運行狀態,否則需要檢查其錯誤所在,必要時可使用“kubeadm reset”命令重置之後重新進行集群初始化。
另外,使用“kubectl get nodes”命令能夠獲取集群節點的相關狀態信息,顯示了Master節點的狀態為“NotReady”(未就緒),這是因為集群中尚未安裝網路插件所致,執行完後面的其他步驟後它即自行轉為“Ready”:
註: 此處為已經安裝fannel網路插件後的結果
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 21h v1.13.1
node1 Ready <none> 63m v1.13.1
master節點部署網路插件fannel
基於kubeadm部署時,flannel同樣運行為Kubernetes集群的附件,以Pod的形式部署運行於每個集群節點上以接受Kubernetes集群管理。
事實上,也可以直接將flannel程式包安裝並以守護進程的方式運行於集群節點上,即以非托管的方式運行。部署方式既可以是獲取其資源配置清單於本地而後部署於集群中,也可以直接線上進行應用部署。
部署命令是“kubectlapply”或“kubectlcreate”,例如,下麵的命令將直接使用線上的配置清單進行flannel部署:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
參考 https://github.com/coreos/flannel
至此master節點就完成了!
node節點加入
Master各組件運行正常後即可將各Node添加至集群中。配置節點時,需要事先參考前面“設置容器運行環境”和“設定Kubernetes集群節點”兩節中的配置過程設置好Node主機,而後即可在Node主機上使用“kubeadmjoin”命令將其加入集群中。
kubeadm join 192.168.18.64:6443 --token 4mvox7.5l6fgyyqo761yxyf --discovery-token-ca-cert-hash sha256:1cd687ae5837b85a48f9ca93873aa67b30d29b1584db3b1f2ede946506735035
提供給APIServer的bootstraptoken認證完成後,kubeadmjoin命令會為後續Master與Node組件間的雙向ssl/tls認證生成私鑰及證書簽署請求,並由Node在首次加入集群時提交給Master端的CA進行簽署。
預設情況下,kubeadm配置kube-apiserver啟用了bootstrapTLS功能,並支持證書的自動簽署。於是,kubelet及kube-proxy等組件的相關私鑰和證書文件在命令執行結束後便可自動生成,它們預設保存於/var/lib/kubelet/pki目錄中。
在每個節點上重覆上述步驟就能夠將其加入集群中。所有節點加入完成後,即可使用“kubectlgetnodes”命令驗證集群的節點狀態,包括各節點的名稱、狀態就緒與否、角色(是否為節點Master)、加入集群的時長以及程式的版本等信息:
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 21h v1.13.1
node1 Ready <none> 79m v1.13.1
重新生成用於節點加入集群的認證命令
如果忘記了節點加入集群的認證命令,需要在master節點通過kubeadm tokem list
獲取認證令牌,再生成驗證CA公鑰的哈希值
[root@master ~]# kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
4mvox7.5l6fgyyqo761yxyf 12m 2019-01-11T18:08:33+08:00 authentication,signing The default bootstrap token generated by 'kubeadm init'. system:bootstrappers:kubeadm:default-node-token
[root@master ~]# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
1cd687ae5837b85a48f9ca93873aa67b30d29b1584db3b1f2ede946506735035
將上述命令生成的值合為如下命令:
kubeadm join 192.168.18.64:6443 --token TOKEN --discover-token-ca-cert-hash sha256:HASH
即為
kubeadm join 192.168.18.64:6443 --token 4mvox7.5l6fgyyqo761yxyf --discover-token-ca-cert-hash sha256:1cd687ae5837b85a48f9ca93873aa67b30d29b1584db3b1f2ede946506735035
一些坑
[root@node2 ~]# kubeadm join 192.168.18.64:6443 --token 4mvox7.5l6fgyyqo761yxyf --discovery-token-ca-cert-hash sha256:1cd687ae5837b85a48f9ca93873aa67b30d29b1584db3b1f2ede946506735035
[preflight] Running pre-flight checks
[WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06
[WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service'
[preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
[ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
node節點加入集群時
第一個warnning是版本驗證問題,不用管
第二個warnning前面說到過,kubectl開機自啟動是kubeadm的強制要求
error問題
[root@node2 ~]# vim /proc/sys/net/bridge/bridge-nf-call-iptables
[root@node2 ~]# vim /etc/sysctl.conf
[root@node2 ~]# echo "1" >/proc/sys/net/ipv4/ip_forward
[root@node2 ~]# sysctl -p /etc/sysctl.conf