k8s 集群部署ansible方式

一、集群配置与分布

IP Hostname Role CPU Memory
10.0.43.71 k8s-m1 master 2 16G
10.0.43.72 k8s-m2 master 2 16G
10.0.43.73 k8s-m3 master 2 16G
10.0.43.74 k8s-n1 worker 2 16G

二、安装准备

2.1 准备工作

  • 升级centos7内核
  • 配置集群免密登录
# 更改主机名(集群所有机器)
[root@k8s-m1 ~]# hostnamectl set-hostname k8s-m1
[root@k8s-m1 ~]# vi /etc/hosts
[root@k8s-m1 Kubernetes-ansible]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1   k8s-m1
10.0.43.71  k8s-m1
10.0.43.72  k8s-m2
10.0.43.73  k8s-m3
10.0.43.74  k8s-m4
# 配置ssh免密登录(3台)
[root@k8s-m1 ~]# ssh-keygen -t rsa
# 主节点
[root@k8s-m1 ~]# cd .ssh
[root@k8s-m1 .ssh]# ls
id_rsa  id_rsa.pub
[root@k8s-m1 .ssh]# cat id_rsa.pub >> authorized_keys
# 从节点
[root@k8s-m2 ~]# ssh-copy-id -i k8s-m1
[root@k8s-m3 ~]# ssh-copy-id -i k8s-m1
[root@k8s-n1 ~]# ssh-copy-id -i k8s-m1
# 主节点
[root@k8s-m1 ~]# chmod 600 .ssh/authorized_keys
[root@k8s-m1 ~]# scp /root/.ssh/authorized_keys k8s-m2:/root/.ssh/
[root@k8s-m1 ~]# scp /root/.ssh/authorized_keys k8s-m3:/root/.ssh/
[root@k8s-m1 ~]# scp /root/.ssh/authorized_keys k8s-n1:/root/.ssh/
测试免密登录

2.2 下载脚本(主节点中某一台)

yum install -y git && \
git clone --recurse-submodules https://github.com/zhangguanzhang/Kubernetes-ansible.git -b v1.13

进入脚本目录

[root@k8s-m1 ~]# cd Kubernetes-ansible
[root@k8s-m1 Kubernetes-ansible]# vi inventory/hosts 

为脚本运行改配置

修改inventory/hosts

  • inventory目录存放了简单的example可以参考下,这里介绍下一些其他场景。
  • 如果master的机器网卡名不一样可以下面这样写INTERFACE_NAME
  • [etcd]不写的话默认在master的每个成员上部署,etcd的名字请写clusterName
  • 如果机器系统准备好的时候就设置了hostname则删掉hostname=xxx的部分
[master]
10.0.43.71 hostname=k8s-m1 nodename=10.0.43.71 clusterName=etcd-001
10.0.43.72 hostname=k8s-m2 nodename=10.0.43.72 clusterName=etcd-002
10.0.43.73 hostname=k8s-m3 nodename=10.0.43.73 clusterName=etcd-003

[node]
10.0.43.74 hostname=k8s-n1 nodename=10.0.43.74
#172.16.1.7 hostname=k8s-n2 nodename=172.16.1.7

如果每台机器密码不一样参照inventory/hosts最下面那样写

修改group_vars/all.yml


这里介绍一些可能需要修改的字段

  • ansible_ssh_pass为ansible基于ssh的密码

  • VIP为HA的vip

  • certSANs是证书里的域名和预留ip,默认的不要动,只能新加

  • nodeStatusUpdatehttps://github.com/zhangguanzhang/Kubernetes-ansible/wiki/nodeStatusUpdate

  • KUBE_VERSIONETCD_version 是给ds的yaml用,二进制需要改版本的话改下载脚本而不是这里,以及这俩变量用来判断渲染一些yaml文件

  • flanneld.type如果不是云上而是在自己的机房或者虚拟化虚机跑, 可以把vxlan模式改成host-gw模式

  • 如果未来会部署多套集群,pod和svc的cidr最好要提前分配下不要整成默认的10.96和10.244,可能未来会把两个集群的pod整成互通,关于cidr不要乱写,例如10.95.0.0/12实际上是在10.80.0.0/12的范围里,不会确定可以在线找个cidr计算下

  • 某些用户例如三台机器都是master+node,没有纯node,想在ipvs模式下从VIP:nodePort去访问集群暴露的服务的话, 记得VIP_NETMASK改成32,原因见 https://github.com/kubernetes/kubernetes/issues/75443 ,不改掩码的话也可以配置roles/CoreAddons/templates/kube-proxy.conf.j2指定bind范围

  • 修改网络模式

nodePortAddresses:
  - 172.16.1.0/24 #根据实际cidr写

安装ansible

[root@k8s-m1 Kubernetes-ansible]# bash scripts/Install-ansible.sh

离线安装ansible的话可以在页面找最新版本 https://releases.ansible.com/ansible/rpm/release/epel-7-x86_64/, 把rpm包先下载下来用yum解决依赖

yum install wget -y 1 > /dev/null
wget https://releases.ansible.com/ansible/rpm/release/epel-7-x86_64/ansible-2.8.5-1.el7.ans.noarch.rpm
yum localinstall ansible-2.8.5-1.el7.ans.noarch.rpm -y

测试ansible是否可达机器

[root@k8s-m1 Kubernetes-ansible]# ansible all -m ping
10.0.43.74 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.43.71 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.43.73 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.43.72 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

三、k8s集群安装

3.1 谨慎用法

Kubernetes-ansible目录里

01-setup.yml

# 运行
[root@k8s-m1 Kubernetes-ansible]# ansible-playbook 01-setup.yml

该步骤会设置基础设置+安装时间同步并重启生效,有些系统自带dnsmasq,这里出现Could not find rhe request service dnsmasq忽略。喜欢测试最新内核的人可以带上-e 'kernel=true'会升级到最新的内核。

执行完后再连上去在剧本目录运行ansible all -m shell -a date看看连通性和时间是否一致,时间不一致则检查chrony服务

02-docker.yml

# 运行
[root@k8s-m1 Kubernetes-ansible]# ansible-playbook 02-docker.yml

根据group_vars/all.ymldocker.version从aliyun使用yum模块安装docker-ce,如果出现错误可以再来一次,单独为某个节点安装可以运行ansible-playbook 02-docker.yml -e 'run=172.16.1.10',这个也可以为非k8s以外的机器安装docker。如果机器的docker服务在运行会不安装docker,仅仅配置配置+重启,想强制升级带上'-e force=true'

1.14-1.15,<1.16.3的版本使用19.03.3以下docker且cg驱动为systemd因为runc报错耗cpu和内存,该bug在19.03.3+修复,如果是低版本的docker,可以升级docker后再升级下containerd.io版本

# 不需运行
$ rpm -qa | grep containerd.io
containerd.io-1.2.10-3.2.el7.x86_64

03-get-binaries.sh

[root@k8s-m1 Kubernetes-ansible]# bash 03-get-binaries.sh all
  • 这步不是剧本,手动运行bash 03-get-binaries.sh all: 通过docker下载k8s和etcd的二进制文件还有cni插件,觉得不信任可以自己其他方式下载。
  • cni压缩包放剧本目录,二进制文件放/usr/local/bin/
  • 如果是运行剧本机器不是第一个master节点,可以利用上面02的-e 'run=localhost'安装完docker后运行此步下载
  • 想下载同大版本内的小版本号则更改脚本里的版本号

04-tls.yml

运行ansible-playbook 04-tls.yml

生成证书和管理组件的kubeconfig,kubeconfig生成依赖kubectl命令,此步确保已经下载有kubectl.

05-etcd.yml

运行ansible-playbook 05-etcd.yml

06-HA.yml

运行ansible-playbook 06-HA.yml

keepalived+haproxy, haproxy七层去check apiserver, 四层代理+VIP来高可用 https://zhangguanzhang.github.io/2019/03/11/k8s-ha/

07-master.yml

运行ansible-playbook 07-master.yml

[root@k8s-m1 Kubernetes-ansible]# kubectl get cs
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok                  
controller-manager   Healthy   ok                  
etcd-1               Healthy   {"health":"true"}   
etcd-2               Healthy   {"health":"true"}   
etcd-0               Healthy   {"health":"true"}   

08-bootstrap.yml

运行ansible-playbook 08-bootstrap.yml

生成bootstrap文件给kubelet注册用

09-node.yml

运行ansible-playbook 09-node.yml

kubelet,执行完后看看kubectl get node有没有(notReady为正常),没有就debug,如何debug见 https://github.com/zhangguanzhang/Kubernetes-ansible/wiki/systemctl-running-debug

10-addon.yml

运行ansible-playbook 10-addon.yml

此步部署kube-proxy,flannel,coredns,metrics-server。如果flannel二进制跑请运行前下载二进制文件bash 03-get-binaries.sh flanneld,daemonset的话提前拉取镜像使用命令拉取ansible Allnode -m shell -a 'curl -s https://zhangguanzhang.github.io/bash/pull.sh | bash -s -- quay.io/coreos/flannel:v0.11.0-amd64', flanneld错误的话请把debug的错误信息提交到issue里

3.2 勇者部署(与3.1任选一种)

  • 运行完01和02以及03-get-binaries.sh后执行ansible-playbook deploy.yml

3.3 给机器打role

kubectl label node node_ip node-role.kubernetes.io/master=master
kubectl label node node_ip node-role.kubernetes.io/node=worker
# 测试
[root@k8s-m1 Kubernetes-ansible]# kubectl label node 10.0.43.71 node-role.kubernetes.io/master=master
node/10.0.43.71 labeled
[root@k8s-m1 Kubernetes-ansible]# kubectl label node 10.0.43.72 node-role.kubernetes.io/master=master
node/10.0.43.72 labeled
[root@k8s-m1 Kubernetes-ansible]# kubectl label node 10.0.43.73 node-role.kubernetes.io/master=master
node/10.0.43.73 labeled
[root@k8s-m1 Kubernetes-ansible]# kubectl label node 10.0.43.74 node-role.kubernetes.io/worker=worker
node/10.0.43.74 labeled
[root@k8s-m1 Kubernetes-ansible]# kubectl get nodes
NAME         STATUS   ROLES         AGE     VERSION
10.0.43.71   Ready    master        2m38s   v1.13.12
10.0.43.72   Ready    master        2m39s   v1.13.12
10.0.43.73   Ready    master        2m39s   v1.13.12
10.0.43.74   Ready    node,worker   2m39s   v1.13.12

3.4 添加node

  1. 在当前的ansible目录改hosts,添加[newNode]分组写上成员和信息,role是复用的,所以不要在此时修改一些标志位参数,例如flanneld.type和bin
  2. 执行ansible-playbook setup.yml -e 'run=newNode', 然后等待重启完可以ping通后执行ansible-playbook addNode.yml
  3. 然后查看是否添加上

四、k8s中部署nginx测试

[root@master0 mgc]# cat nginx-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
[root@master0 mgc]# cat nginx-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  ports:
  - port: 8000
    targetPort: 80
    nodePort: 31111
  selector:
    app: nginx
[root@k8s-m1 k8s-nginx]# ls
nginx-deploy.yaml  nginx-svc.yaml
[root@k8s-m1 k8s-nginx]# kubectl apply -f nginx-svc.yaml 
service/nginx created
[root@k8s-m1 k8s-nginx]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx created
[root@k8s-m1 k8s-nginx]# kubectl get pods
NAME                     READY   STATUS              RESTARTS   AGE
nginx-7db75b8b78-6km6h   0/1     ContainerCreating   0          29s
nginx-7db75b8b78-x92lt   0/1     ContainerCreating   0          29s

五、问题

对于无法通过节点ip、服务ip、虚拟VIP访问的问题,解决如下

# 所有节点执行
sed -ri 's#"ipvs"#"iptables"#' /etc/kubernetes/kube-proxy.conf
# 所有节点,修改配置文件
[root@k8s-m1 nginx]# vi /lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-proxy \
  --hostname-override=10.0.43.71 \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes/kube-proxy \
  # 增加ipvx配置
  --proxy-mode=ipvs \
  # 指定配置文件
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \
  --v=2

Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target
# 重启
systemctl daemon-reload  && systemctl restart kube-proxy

六、部署可视化监控工具kuboard

安装

kubectl apply -f https://kuboard.cn/install-script/kuboard.yaml

查看kuboard运行状态

[root@k8s-m1 nginx]# kubectl get pods -l k8s.eip.work/name=kuboard -n kube-system
NAME                       READY   STATUS    RESTARTS   AGE
kuboard-6b86c9757b-dn8rm   1/1     Running   0          69s

获取管理员token

[root@k8s-m1 nginx]# kubectl -n kube-system get secret $(kubectl -n kube-system get secret | grep kuboard-user | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d
eyJhbGciOiJFUzUxMiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tYjI4aDIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMWJjNzI1M2MtOTM2Yi0xMWVhLTlmMDAtMGNkYTQxMWQ3ZTQ4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.AbGjx3zSoAeECge5J5RRLRyMl_U6KyA9MRGJ9CukbwxEWaeJv-QkhH39vFCsHpmWrzfPY-Whau2NNXJfohYtA9fcAP0iokMJRu2h_i9Ftx7cSa0jBN9jsUCIqq0EKxjmzis4C-DY_qX0H4yXzDiagF21baHbAquz3e86KmgJdKIZVm25

访问

http://任意一个Worker节点的IP地址:32567/