Skip to content

写给公司同事看的部署步骤

zhangguanzhang edited this page Jul 24, 2020 · 15 revisions

前言

        这套ansible的大体步骤都是kubeadm的执行步骤抠出来按照标准来实现,cs的三个管理组件以及node上的kube-proxycni(目前使用的是flannel)都不使用staticPod和ds来部署。因为 kubeadm 的 join 和 init 都是取默认路由 bind 在多网卡下会有问题,因为生产环境都是多网卡,减少不必要的 bind 不能写0.0.0.0

        写到现在大体的逻辑都写完了,后续都是更新细节性的问题。涉及到kind:APIService这个资源对象的反向代理,master上需要运行cni(flannel,calico)以及kubelet,不想master调度pod可以加污点

部署

机器侧的提前一些配置

        系统尽量采用centos7的最新版本(7.4和7.4以下使用docker会出现很多莫名奇妙的问题),下面文章都会以centos上做说明。ubuntu不熟悉,但是如果你(看完后)对步骤的目的都熟悉了后可以自己为ubuntu写一套

  • 配置最低建议2c4g,这个值来源于kubeadm的配置checks
  • 静态ip配置,多网卡就做bond,bond名最好都一样,如果部署机器是底层openstack网络下的虚机的话,由于k8s的HA是基于VIP实现的高可用,默认ip和mac绑定会导致VIP无法外部通信,需要解绑ip和mac,见文章 基于openstack的ecs上使用vip
  • dns改成内网的dns或者不是纯内网环境则使用公网的,确保/etc/resolv.conf里没有nameserver 127.0.0.xsearch的行
  • 如果纯内网则要准备一个ntp server,因为集群是tls的时间误差会认证失败

准备文件

        准备文件可以自己提前下载了,涉及到docker镜像的部分可以自己拉取离线save。主要思想是部署,要清楚每一步的目的是干啥,如果我写的步骤不适合当前的场景,你有更好的实现手段(甚至不使用ansible)能达到相同目的的话可以完全使用你的喜好。如果想完全离线的话,要注意以下这几个部分:

  • ansible依赖,可以rpm包解决
  • 系统一些包的基础依赖 --- 内网镜像仓库
  • docker这部分 --- 可以镜像阿里云的repo,或者二进制包+systemd(这样的话得改ansible)
  • docker镜像 --- 要么把相关docker镜像save成tar包,但是这样镜像被gc掉了会很麻烦,推荐提前推送到内网的docker镜像仓库上。
  • k8s相关的二进制文件可以提前准备好

准备好ansible文件

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

        k8s版本号为vx.y.z,一般我们叫vx.y版本,例如v1.16,这个属于大版本。同一个大版本内配置全部是兼容的,只修复功能性的bug问题,不会新增功能,不同大版本(cs和node相关的)配置文件会有细微性的差距(所以kubeadm为了避免这个都是保留最小能运行的参数,这样不符合我们的预期),所以我仓库按照大版本来做分支名。-b后面接需要安装的版本         因为各个版本直接差异性主要是k8s管理组件,所以我ansible的很多文件都是采用git submodules来复用

        对于版本选择,不要盲目追求新的。如果最新版本的小版本号小于4就使用上一个大版本的最后一个版本,像之前v1.14弄错了内核模块名字,v1.18的ipvs模块错误。如果是升级集群最好要对各种k8s的kind:xxxapiVersion都调查下是否废弃或者并入到其他api组或者字段变化。

配置ansible主机连接信息

  1. 安装ansible,需要外网,离线则使用rpm包 https://releases.ansible.com/ansible/rpm/release/epel-7-x86_64/
bash scripts/Install-ansible.sh
  1. 修改 group_vars/all.yml里ssh的密码
ansible_ssh_pass: 'zhangguanzhang'
  1. 修改inventory/hosts 该目录里还有其他的情况的示例,如果hostname已经设置了就删掉hostname=xxx。下面例子是三个master也做node的内容
# kubelet's node name must be `[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*`
# nodename used by k8s cluster, you also could use the ip address 
# nodename to k8s, clusterName to etcd
[master]
172.16.1.3 hostname=k8s-m1 nodename=172.16.1.3 clusterName=etcd-001 
172.16.1.4 hostname=k8s-m2 nodename=172.16.1.4 clusterName=etcd-002
172.16.1.5 hostname=k8s-m3 nodename=172.16.1.5 clusterName=etcd-003

#[newMaster]
#172.16.1.12 hostname=k8s-m4 nodename=k8s-m4

[Master:children]
master

[Allnode:children]
Master

#如果各台密码和端口不通请按照下面格式填写好并注释掉group_vars/all.yml里的ansible_ssh_pass的那一行
#172.16.1.13 ansible_ssh_pass=password ansible_ssh_port=666
#172.16.1.14 ansible_ssh_pass=password233 ansible_ssh_port=68
  1. 使用ping模块测试下ansible可达主机否,pong则可达
ansible all -m ping

部署

        !!!!!主要是运行ansible的剧本,全部得在clone下来的文件根目录里,也就是目录Kubernetes-ansible里运行后面的剧本和ansible命令!!!!!!!!!。

01-setup

        按照系统标准(很多非运维的人改主文件而不是子配置文件,有对应daemon程序但是去写rc.local等)来设置系统和配置参数,以及安装k8s的少部分依赖和后续运维时候的一些工具

编辑文件group_vars/all.yml,如果内网则使用内网的ntp server

ntp_servers: 
  - 'cn.pool.ntp.org'
  - 's1b.time.edu.cn'

kernel: !!bool false # 这个是内核升级,默认为false。如果想自己尝试新内核可以试试,前提你得对配置启动内核和相关知识有一定了解下才建议设置成 true

运行

ansible-playbook 01-setup.yml

根据docker的检查脚本centos要配置一个user namespace的内核参数,所以此步执行完了会重启。如果出现不ok的,例如yum直连公网安装一些依赖会没成功,假如三台,有台172.16.1.2没成功执行完。等运行ansible的机器正常重启上来后单独继续执行

ansible-playbook 01-setup.yml -e run=172.16.1.2

全部机器ok后利用shell模块看下连通性和时间是否一致,不一致则检查chrony服务

ansible all -m shell -a date

02-docker

        此步是添加aliyun的docker-ce源,根据docker的官方安装脚本逻辑里抠出来的步骤,官方脚本里只有直连或者使用阿里云的源选项。以及设置docker补全脚本和修正FORWARD

编辑文件group_vars/all.yml

docker:
  version: '19.03' # docker版本,如果要各个环境严格一致得写全版本号,例如`19.03.8`
#  Environments:
#    - HTTP_PROXY=http://127.0.0.1:8080 # 有docker使用代理拉镜像需求的话
  dataDir: /var/lib/docker  # 有条件这个目录单独分个区
  execOpts:
    - 'native.cgroupdriver=systemd'
  registryMirrors: # 公网的一些镜像源
    - https://fz5yth0r.mirror.aliyuncs.com
    - https://dockerhub.mirrors.nwafu.edu.cn
    - https://docker.mirrors.ustc.edu.cn/
    - https://reg-mirror.qiniu.com
    - http://hub-mirror.c.163.com/
    - https://registry.docker-cn.com
# 内网harbor之类的镜像仓库,可以按照格式填写
#  insecureRegistries:
#    - 100.64.2.52:9999
#    - 100.64.1.31:9999

运行

ansible-playbook 02-docker.yml

出现某个节点docker安装失败的则单独尝试

ansible-playbook 02-docker.yml -e run=172.16.1.2

如果有私有仓库,可能需要下面步骤,先每个机器登录私网仓库,不知道就询问公司的相关人员登录信息

docker login harbor-local.unicloudsrv.com -u '$username' -p '$password'

03-get binary file

        我有用travis-ci的runner来把k8s的相关文件压缩包做成docker镜像推送到dockerhub上,此步是pull 相关镜像,然后run起来后docker cp出相关文件。相关文件有:

  • k8s压缩包,cp出来后解压到/usr/local/bin/
  • cni plugins包,用于ansible分发到各个node上的/opt/cni/bin/
  • docker cp出镜像的etcd二进制文件,flannel二进制文件

如果你要整离线则可以看脚本加载的那些下载方法和路径,也可以改03-get-binaries.sh里版本号来下载同一个大版本内前面或者后面的小版本。

运行,dockerhub可能会很久才拉去下来。

bash 03-get-binaries.sh all

04-tls

        这步生成很多步骤的证书和kubeconfig,依赖opensslkubectl,kubectl是上一步下载的。这步的证书具体信息有兴趣可以看我博客 https://zhangguanzhang.github.io/2019/03/03/kubernetes-1-13-4/#%E5%BB%BA%E7%AB%8B%E9%9B%86%E7%BE%A4CA-keys-%E4%B8%8ECertificates

运行

ansible-playbook 04-tls.yml

05-etcd

        二进制使用systemd管理部署etcd,配置文件按照etcd的github仓库的yaml配置示例文件,而不是写systemd里的命令行参数,etcd的参数值也可以环境变量。此步不会开启v2的etcd api,因为现在k8s都是用v3 api存储,v2和v3共存会无法恢复备份         同时生成alias脚本/etc/profile.d/etcd.sh,可以使用etcd_v3别名来操作集群。同时会生成定时备份脚本在crontab里

有需要就编辑文件group_vars/all.yml

etcd:
  dataDir: /var/lib/etcd # 数据文件目录
  initialClusterToken: 'etcd-k8s-cluster' # 写个字符串
  backup: 
    dataDir: /opt/etcd_bak  # 备份目录
    scriptDir: /etc/etcd/   # 备份脚本存放目录
    count: "4"              # 最大保留几个备份

运行

ansible-playbook 05-etcd.yml

查看集群状态

source /etc/profile.d/etcd.sh  # 只有这次需要source,后续都不用source
etcd-ha # 这个别名命令查看集群信息,默认etcd都会部署在master上

下面是输出

+-------------------------+------------------+---------+---------+-----------+-----------+------------+
|        ENDPOINT         |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+-------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://172.16.1.3:2379 | a7aaefdac178d910 |  3.3.18 |   10 MB |     false |       179 |    5492243 |
| https://172.16.1.4:2379 | bd8b8913565899ce |  3.3.18 |  9.9 MB |     false |       179 |    5492243 |
| https://172.16.1.5:2379 | 5b602b26bf6b6050 |  3.3.18 |   10 MB |      true |       179 |    5492243 |
+-------------------------+------------------+---------+---------+-----------+-----------+------------+

06-HA

        keepalived+haproxy, haproxy在apiserver的web七层/healthz路由去check, 四层代理+VIP来高可用。 原理见 https://zhangguanzhang.github.io/2019/03/11/k8s-ha/         如果是openstack的虚机,记得解绑ip和mac的绑定,否则vip无法外部通信

有需要就编辑文件group_vars/all.yml

VIP: '172.16.1.240' # 选同一个掩码网络下未被使用的ip即可,可以提前ping下看看使用了没有
VIP_NETMASK: 24   # 网络的掩码
INTERFACE_NAME: eth0  # vip应该在哪张网卡上,如果有做bond则写bond的名,单网卡就网卡的名

运行

ansible-playbook 06-HA.yml

运行完在没有vip的机器上ping下vip地址看icmp可达不

07-master -- Component

        master的三个管理组件

有需要就编辑文件group_vars/all.yml

# 下面前三个要改就一起改
SvcCIDR: 10.96.0.0/12
KubernetesClusterSVCIP: 10.96.0.1 # 默认占据SVC段的第一个ip,用于证书里SAN值
ClusterDns: 10.96.0.10  #修改SvcCIDR的画确保它的ip在CIDR内
PodCIDR: 10.244.0.0/16  # pod的ip的cidr
ServiceNodePortRange: 30000-32767  # nodePort的范围
ClusterDomain: cluster.local # 如果不懂这个作用就不要修改

运行

ansible-playbook 07-master.yml

查看状态,v1.16目前到在get cs显示unkown是官方废弃的, 不影响使用。废弃后在大家呼吁下又在1.17版本回来了,非1.16版本cs是有status的

$ kubectl get cs
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-2               Healthy   {"health": "true"}
etcd-1               Healthy   {"health": "true"}
etcd-0               Healthy   {"health": "true"}

08-bootstrap

bootstrap用于注册和扩展node 运行

ansible-playbook 08-bootstrap.yml

09-kubelet -- node

配置和启动kubelet 有需要就编辑文件group_vars/all.yml,infra_image如果离线则改成内网镜像仓库上的镜像

infra_image: 'zhangguanzhang/pause-amd64:3.2'

私有镜像的话会有个bug,私有镜像则提前docker login登录内网镜像仓库,然后运行拉取下镜像ansible all -m shell -a 'docker pull xxx/xxxx/pause-amd64:3.2'

运行

ansible-playbook 09-node.yml

稍等一会儿后查看node,notReady为正常,因为此时还未部署cni(剧本里是flannel)。如果一致啥都没输出则debug kubelet,见 systemctl debug

kubectl get node

10-addon --> kube-proxy,flannel,coredns,metrics-server

kube-proxy在kubelet后部署,然后再是cni(热门的是calico和flannel),coredns为集群内部提供dns服务,metrics-server是kubectl top命令信息来源提供。

有需要就编辑文件group_vars/all.yml,如果是云下物理机或者解绑了ip和mac的虚机,推荐把vxlan改成host-gw

flanneld:
  img: quay.io/coreos/flannel:v0.11.0-amd64 # 不重要
  bin: !!bool true  # 不懂就不要改,默认二进制运行flannel
  type: vxlan # or set the value to 'host-gw'  如果是云下物理机或者解绑了ip和mac的虚机,推荐使用host-gw
  healthzPort: 8471
#  logDir: /var/log/flanneld  # 新版无`log_dir参数`,详情 https://github.com/coreos/flannel/issues/1115
  logLevel: 2

三台机器都是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写

如果把这里的coredns和metrics-server使用内网镜像则需要创建k8s的imagePullSecret,给默认和kube-system俩ns创建并给sa patch下

kubectl create secret docker-registry harbor-local \
    --docker-server=harbor-local.unicloudsrv.com  \
    --docker-username=xxxx \
    --docker-password=xxxxx
kubectl patch serviceaccount default \
    -p '{"imagePullSecrets": [{"name": "harbor-local"}]}'
kubectl -n kube-system create secret docker-registry harbor-local \
    --docker-server=harbor-local.unicloudsrv.com  \
    --docker-username=xxxx \
    --docker-password=xxxxx
kubectl -n kube-system   serviceaccount default \
    -p '{"imagePullSecrets": [{"name": "harbor-local"}]}'

pause镜像使用私有仓库的则有个bug,见 https://github.com/kubernetes/kubernetes/issues/90503 推荐把这个镜像放到内网仓库一个公开的repo里 运行

ansible-playbook 10-addon.yml

等镜像拉取

kubectl -n kube-system get po -o wide

确保coredns的pod running了后,测试下

time    curl -I 10.96.0.10:9153/metrics

如果是real 1m3秒的话请查看文章 https://zhangguanzhang.github.io/2020/05/23/k8s-vxlan-63-timeout/ 或者使用v1.18.6, v1.16.13, v1.17.9以上的kube-proxy试下