一、使用Kubespray部署Kubernetes生产集群
1. 服务器说明
1.1. 节点要求
节点数 >=3台
CPU >=2
Memory >=2G
安全组:关闭(允许节点之间任意端口访问,以及ipip隧道协议通讯)
计划使用阿里云的同学看过来:
多个节点同时购买,同一个账号,同一个地域,同一个可用区,保证内网ip可以联通!
1.2. 演示环境说明
我们这里使用的是三台centos 7.5的虚拟机,具体信息如下表:
系统类型 | IP地址 | 节点角色 | CPU | Memory | Hostname |
---|---|---|---|---|---|
centos-7.5 | 192.168.18.131 | master | >=2 | >=2G | node-1 |
centos-7.5 | 192.168.18.132 | master | >=2 | >=2G | node-2 |
centos-7.5 | 192.168.18.133 | worker | >=2 | >=2G | node-3 |
2. 系统设置(所有节点)
注意:所有操作使用root用户执行
2.1 主机名
主机名必须合法,并且每个节点都不一样(建议命名规范:数字+字母+中划线组合,不要包含其他特殊字符)。
# 查看主机名
$ hostname
# 修改主机名
$ hostnamectl set-hostname <your_hostname>
2.2 关闭防火墙、selinux、swap,重置iptables
# 关闭selinux
$ setenforce 0
$ sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config
# 关闭防火墙
$ systemctl stop firewalld && systemctl disable firewalld
# 设置iptables规则
$ iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT
# 关闭swap
$ swapoff -a && free –h
# 关闭dnsmasq(否则可能导致容器无法解析域名)
$ service dnsmasq stop && systemctl disable dnsmasq
2.3 k8s参数设置
制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0
vm.overcommit_memory = 1
EOF
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf
注意,如果这里有报错,输入
modprobe br_netfilter
参见文档:
配置内核参数报sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory
2.4 移除docker相关软件包(可选)
$ yum remove -y docker*
$ rm -f /etc/docker/daemon.json
3. 使用kubespray部署集群
这部分只需要在一个 操作 节点执行,可以是集群中的一个节点,也可以是集群之外的节点。甚至可以是你自己的笔记本电脑。我们这里使用更普遍的集群中的任意一个linux节点。
3.1 配置免密
使 操作 节点可以免密登录到所有节点
# 1. 生成keygen(执行ssh-keygen,一路回车下去)
$ ssh-keygen
# 2. 查看并复制生成的pubkey
$ cat /root/.ssh/id_rsa.pub
# 3. 分别登陆到每个节点上,将pubkey写入/root/.ssh/authorized_keys
$ mkdir -p /root/.ssh
$ echo "<上一步骤复制的pubkey>" >> /root/.ssh/authorized_keys
我这里在node-1上进行操作。
进行免登陆测试,在node-1上进行登录node-2和node-3
3.2 依赖软件下载、安装
这个也只要在操作节点执行,这里我在node-1操作。
# 安装基础软件
$ yum install -y epel-release python36 python36-pip git
# 下载kubespray源码
$ wget https://github.com/kubernetes-sigs/kubespray/archive/v2.15.0.tar.gz
# 解压缩
$ tar -xvf v2.15.0.tar.gz && cd kubespray-2.15.0
# 安装requirements
$ cat requirements.txt
$ pip3.6 install -r requirements.txt
## 如果install遇到问题可以先尝试升级pip
## $ pip3.6 install --upgrade pip
这里报错,升级下pip
pip3.6 install --upgrade pip
然后重新执行
pip3.6 install -r requirements.txt
这样好了。
3.3 生成配置
项目中有一个目录是集群的基础配置,示例配置在目录inventory/sample中,我们复制一份出来作为自己集群的配置
# copy一份demo配置,准备自定义
$ cp -rpf inventory/sample inventory/mycluster
由于kubespray给我们准备了py脚本,可以直接根据环境变量自动生成配置文件,所以我们现在只需要设定好环境变量就可以啦
# 使用真实的hostname(否则会自动把你的hostname改成node1/node2...这种哦)
$ export USE_REAL_HOSTNAME=true
# 指定配置文件位置
$ export CONFIG_FILE=inventory/mycluster/hosts.yaml
# 定义ip列表(你的服务器内网ip地址列表,3台及以上,前两台默认为master节点)
$ declare -a IPS=(192.168.18.131 192.168.18.132 192.168.18.133)
# 生成配置文件
$ python3 contrib/inventory_builder/inventory.py ${IPS[@]}
注意,这里的ip改成自己的ip
3.4 个性化配置
配置文件都生成好了,虽然可以直接用,但并不能完全满足大家的个性化需求,比如用docker还是containerd?docker的工作目录是否用默认的/var/lib/docker?等等。当然默认的情况kubespray还会到google的官方仓库下载镜像、二进制文件,这个就需要你的服务器可以上外面的网,想上外网也需要修改一些配置。
# 定制化配置文件
# 1. 节点组织配置(这里可以调整每个节点的角色)
$ vi inventory/mycluster/hosts.yaml
# 2. containerd配置(教程使用containerd作为容器引擎)
$ vi inventory/mycluster/group_vars/all/containerd.yml
# 3. 全局配置(可以在这配置http(s)代理实现外网访问)
$ vi inventory/mycluster/group_vars/all/all.yml
# 4. k8s集群配置(包括设置容器运行时、svc网段、pod网段等)
$ vi inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
# 5. 修改etcd部署类型为host(默认是docker)
$ vi ./inventory/mycluster/group_vars/etcd.yml
# 6. 附加组件(ingress、dashboard等)
$ vi ./inventory/mycluster/group_vars/k8s-cluster/addons.yml
配置文件内容:
1.节点组织配置(这里可以调整每个节点的角色)
vi inventory/mycluster/hosts.yaml
-
containerd配置(教程使用containerd作为容器引擎)
vi inventory/mycluster/group_vars/all/containerd.yml
-
全局配置(可以在这配置http(s)代理实现外网访问)
vi inventory/mycluster/group_vars/all/all.yml
配置代理
-
k8s集群配置(包括设置容器运行时、svc网段、pod网段等)
vi inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
修改地址
修改为containerd
5 修改etcd部署类型为host(默认是docker)
vi ./inventory/mycluster/group_vars/etcd.yml
6 附加组件(ingress、dashboard等)
vi ./inventory/mycluster/group_vars/k8s-cluster/addons.yml
打开darshboard
使用ingress_nginx
3.5 一键部署
配置文件都调整好了后,就可以开始一键部署啦,不过部署过程不出意外会非常慢。 如果您使用的是教程同一个版本建议下使用网盘下载好二进制文件和镜像
网盘下载二进制(可选)
链接: https://pan.baidu.com/s/11eDin8BDJVzGgXJW9e6cog 提取码: mrj9
下载好之后解压到每个节点的根目录即可,解压完成后的目录是/tmp/releases
cd /
tar -zxvf kubespray-k8s-releases-v2.15.0.tar.gz
注意,开始一键部署之前更新下yum,这个不要忘记了!!
sudo yum -y update
一键部署
# -vvvv会打印最详细的日志信息,建议开启
$ ansible-playbook -i inventory/mycluster/hosts.yaml -b cluster.yml -vvvv
经过漫长的等待后,如果没有问题,整个集群都部署起来啦。
下载镜像(可选)
为了减少“一键部署”的等待时间,可以在部署的同时,预先下载一些镜像。
$ curl https://gitee.com/pa/pub-doc/raw/master/kubespray-v2.15.0-images.sh|bash -x
重要:此操作需要确保上面的"一键部署"执行后,并成功安装了containerd后即可手动下载镜像)
最后差不多1小时左右就下载好了。
3.6 清理代理设置
清理代理设置(运行时不再需要代理,删掉代理配置即可)
删除docker的http代理(在每个节点执行)
$ rm -f /etc/systemd/system/containerd.service.d/http-proxy.conf
$ systemctl daemon-reload
$ systemctl restart containerd
删除yum代理
# 把grep出来的代理配置手动删除即可
$ grep 8118 -r /etc/yum*
注意,这里的/etc/yum.conf是要使用vim打开删除红色框或者注释掉。
3.7 安装完查看下各种资源
(1)获取命名空间
kubectl get ns
注意,这里遇到一个问题,就是输入命令后报错,如下:
解决办法,取消代理,每个节点都要执行一下。
unset http_proxy
unset https_proxy
(2)获取命名空间下资源
# 默认命名空间
kubectl get all
kubectl get all -n ingress-nginx
kubectl get all -n kube-node-lease
kubectl get all -n kube-public
kubectl get all -n kube-system
(3)我们发现在执行 kubectl get all -n kube-system,有一个niginx-proxy-node-3
kubectl get all -n kube-system
去node3查一下:
crictl ps
来验证一下这个node3上的这个nginx_proxy是哪里来的,应该是单独启的一个pod
node3上查看
cat /etc/kubernetes/manifests/nginx-proxy.yml
node3上挂载的nginx的配置文件
cat /etc/nginx/nginx.conf
为了实现高可用和负载均衡,只有node3是一个单纯的worker节点,其他2个节点是主节点,6443已经占用了,不会再启动nginx了。
二、集群冒烟测试
1. 创建nginx ds
# 写入配置
cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-ds
labels:
app: nginx-ds
spec:
type: NodePort
selector:
app: nginx-ds
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
selector:
matchLabels:
app: nginx-ds
template:
metadata:
labels:
app: nginx-ds
spec:
containers:
- name: my-nginx
image: nginx:1.19
ports:
- containerPort: 80
EOF
# 创建ds
kubectl apply -f nginx-ds.yml
2. 检查各种ip连通性
# 检查各 Node 上的 Pod IP 连通性
$ kubectl get pods -o wide
# 在每个节点上ping pod ip
$ ping <pod-ip>
# 检查service可达性
$ kubectl get svc
# 在每个节点上访问服务
$ curl <service-ip>:<port>
# 在每个节点检查node-port可用性
$ curl <node-ip>:<port>
3. 检查dns可用性
# 创建一个nginx pod
$ cat > pod-nginx.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:1.19
ports:
- containerPort: 80
EOF
# 创建pod
$ kubectl apply -f pod-nginx.yaml
# 进入pod,查看dns
$ kubectl exec nginx -it -- /bin/bash
# 查看dns配置
root@nginx:/# cat /etc/resolv.conf
# 查看名字是否可以正确解析
root@nginx:/# ping nginx-ds
4. 日志功能
测试使用kubectl查看pod的容器日志
$ kubectl get pods
$ kubectl logs <pod-name>
5. Exec功能
测试kubectl的exec功能
$ kubectl get pods -l app=nginx-ds
$ kubectl exec -it <nginx-pod-name> -- nginx -v
三、 访问dashboard
1. 创建service
$ cat > dashboard-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: dashboard
labels:
app: dashboard
spec:
type: NodePort
selector:
k8s-app: kubernetes-dashboard
ports:
- name: https
nodePort: 30000
port: 443
targetPort: 8443
EOF
$ kubectl apply -f dashboard-svc.yaml
2. 访问dashboard
https://192.168.18.131:30000/
为了集群安全,从 1.7 开始,dashboard 只允许通过 https 访问,我们使用nodeport的方式暴露服务,可以使用 https://NodeIP:NodePort 地址访问 关于自定义证书 默认dashboard的证书是自动生成的,肯定是非安全的证书,如果大家有域名和对应的安全证书可以自己替换掉。使用安全的域名方式访问dashboard。 在dashboard-all.yaml中增加dashboard启动参数,可以指定证书文件,其中证书文件是通过secret注进来的。
- –tls-cert-file
- dashboard.cer
- –tls-key-file
- dashboard.key
3. 登录dashboard
Dashboard 默认只支持 token 认证,所以如果使用 KubeConfig 文件,需要在该文件中指定 token,我们这里使用token的方式登录
# 创建service account
$ kubectl create sa dashboard-admin -n kube-system
# 创建角色绑定关系
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 查看dashboard-admin的secret名字
$ ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')
# 打印secret的token
$ kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}'
生成的token:
eyJhbGciOiJSUzI1NiIsImtpZCI6IlhLS21FX2tOaHJJdzN3ZGx3YjhMcFNrS0EwWVNTUmJrWWtOSnhfanBGcGcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tOTc2eGIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOGU0MzU4ZmEtMDExZS00Zjc2LTgwNWEtODdkNDQ5ZWRlZWM2Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.ogAibpox4FT6JLJVfRbJMamG_mygGk10OiwQR4orazc2amVuJrvowuM-FDp8FtA-XRuKr1zcU6VerCEf1Aklt-ilP2yZWp9sShLifNEBg04H0RiWV4gj61f3wwjzz2OFGDzY1JWB-Y1BQjxKS4D8hGC8ZogEqF28xbK27JGZQUtX4NMgl95LsGAwmBtXBrSWKnXAmdtUNhaaqwiWTTHPvqJxSrk_LsKdbG5L0X4E9Mx8Wl3d_NaRkHY50oCFdUpQm8FxH7D1DUhJC6FfMOahJ216kWgJ0lMdtdcMakflgZrlxnTy6QtaOYXhfxiOdcFVzNFQx0RyAAmf8JKXGHXpOQ
进行登录
登录进来了
查看Pods
查看其中一个
查看日志
下载日志
进入命令行
进行编辑
可以进行删除
四、集群运维
1. Master节点
增加master节点
# 1.编辑hosts.yaml,增加master节点配置
$ vi inventory/mycluster/hosts.yaml
# 2.执行cluster.yml(不要用scale.yml)
$ ansible-playbook -i inventory/mycluster/hosts.yaml cluster.yml -b -v
# 3.重启nginx-proxy - 在所有节点执行下面命令重启nginx-proxy
$ docker ps | grep k8s_nginx-proxy_nginx-proxy | awk '{print $1}' | xargs docker restart
删除master节点
如果你要删除的是配置文件中第一个节点,需要先调整配置,将第一行配置下移,再重新运行cluster.yml,使其变成非第一行配置。举例如下:
# 场景:下线node-1节点
$ vi inventory/mycluster/hosts.yaml
# 变更前的配置
children:
kube-master:
hosts:
node-1:
node-2:
node-3:
# 变更后的配置
children:
kube-master:
hosts:
node-2:
node-1:
node-3:
# 再执行一次cluster.yml
$ ansible-playbook -i inventory/mycluster/hosts.yaml -b cluster.yml
非第一行的master节点下线流程:
# 执行remove-node.yml(不要在hosts.yaml中删除要下线的节点)
$ ansible-playbook -i inventory/mycluster/hosts.yaml remove-node.yml -b -v -e "node=NODE-NAME"
# 同步hosts.yaml(编辑hosts.yaml将下线的节点删除,保持集群状态和配置文件的一致性)
$ vi inventory/mycluster/hosts.yaml
2. Worker节点
增加worker节点
# 刷新缓存
$ ansible-playbook -i inventory/mycluster/hosts.yaml facts.yml -b -v
# 修改配置hosts.yaml,增加节点
$ vi inventory/mycluster/hosts.yaml
# 执行scale添加节点,--limit限制只在某个固定节点执行
$ ansible-playbook -i inventory/mycluster/hosts.yaml scale.yml --limit=NODE-NAME -b -v
删除worker节点
# 此命令可以下线节点,不影响其他正在运行中的节点,并清理节点上所有的容器以及kubelet,恢复初始状态,多个节点逗号分隔
$ ansible-playbook -i inventory/mycluster/hosts.yaml remove-node.yml -b -v -e "node=NODE-NAME-1,NODE-NAME-2,..."
# 同步hosts.yaml(编辑hosts.yaml将下线的节点删除,保持集群状态和配置文件的一致性)
$ vi inventory/mycluster/hosts.yaml
3. ETCD节点
如果要变更的etcd节点同时也是master或worker节点,需要先将master/worker节点按照前面的文档操作下线,保留纯粹的etcd节点
增加etcd节点
# 编辑hosts.yaml(可以增加1个或2个etcd节点配置)
$ vi inventory/mycluster/hosts.yaml
# 更新etcd集群
$ ansible-playbook -i inventory/mycluster/hosts.yaml upgrade-cluster.yml --limit=etcd,kube-master -e ignore_assert_errors=yes -e etcd_retries=10
删除etcd节点
# 执行remove-node.yml(不要在hosts.yaml中删除要下线的节点)
$ ansible-playbook -i inventory/mycluster/hosts.yaml remove-node.yml -b -v -e "node=NODE-NAME"
# 同步hosts.yaml(编辑hosts.yaml将下线的节点删除,保持集群状态和配置文件的一致性)
$ vi inventory/mycluster/hosts.yaml
# 运行cluster.yml给node节点重新生成etcd节点相关的配置
$ ansible-playbook -i inventory/mycluster/hosts.yaml -b cluster.yml
4. 其他常用命令
集群reset
# 运行reset.yml一键清理集群
$ ansible-playbook -i inventory/mycluster/hosts.yaml -b -v reset.yml
自定义play起始点
当我们执行play的过程中如果有问题,需要重新的时候,如果重新执行指令会重新经历前面漫长的等待,这个时候“跳过”功能就显得非常有用
# 通过--start-at-task指定从哪个task处开始执行,会跳过前面的任务,举例如下
$ ansible-playbook --start-at-task="reset | gather mounted kubelet dirs"
忽略错误
当有些错误是我们确认可以接受的或误报的,可以配置ignore_errors: true,避免task出现错误后影响整个流程的执行。
# 示例片段如下:
- name: "Remove physical volume from cluster disks."
environment:
PATH: "{{ ansible_env.PATH }}:/sbin"
become: true
command: "pvremove {{ disk_volume_device_1 }} --yes"
ignore_errors: true