使用kubeadm来部署k8s集群
kubernetes 搭建记录
一、环境准备
- 其实这里用CentOS或者是Debian都无所谓,重点是网络要通畅
- 如果网络有问题,那整个过程就麻烦的多
- 所以如果有条件,还是老老实实地用一个Proxy,省事
- 最好的文档就是官方文档
- 搞了一个脚本,用来初始化环境。在CentOS 7下没问题,其他系统不知道
#!/bin/bash
# author: @zhouplus
GCR_REPO_BASEURL="gcr.azk8s.cn/google_containers" #国内gcr镜像源base地址,不要带/后缀
GCR_ORIG_BASEURL="k8s.gcr.io" #谷歌原地址
#添加k8s的源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
#gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
#禁用selinux
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
#防止出错
cat <<EOF > /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
vm.max_map_count=262144
EOF
sysctl --system
#安装所需软件
yum install -y epel-release
yum install -y vim screen iftop iotop htop lrzsz net-tools wget ipvsadm
#安装iscsi,给openebs用
yum install -y iscsi-initiator-utils
systemctl enable iscsid
systemctl start iscsid
#必须关掉swap
swapoff -a
sed -i "s/\/dev\/mapper\/centos-swap/# \/dev\/mapper\/centos-swap/g" /etc/fstab
#关掉防火墙
systemctl disable firewalld
systemctl stop firewalld
iptables -F
iptables -t nat -F
#安装docker
yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io -y
#替换国内源,这里可能需要加上自己的源
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
#加载必要的模块
lsmod | grep br_netfilter
if [ $? -ne 0 ]; then
modprobe br_netfilter
fi
#修改hostname
#hostnamectl set-hostname nodex
#启动docker
systemctl enable docker
systemctl start docker
#安装k8s
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet
#安装k8s所需的docker image
#image_list=$(kubeadm config images list 2> /dev/null | egrep -o '^k8s.*$' | cut -d "/" -f 2)
image_list=$(kubeadm config images list 2> /dev/null | cut -d "/" -f 2)
for image in ${image_list}
do
new_image="${GCR_REPO_BASEURL}/${image}"
echo "pulling ${new_image}..."
docker pull ${new_image} 1>/dev/null
docker tag ${new_image} "${GCR_ORIG_BASEURL}/${image}"
echo "pull and tag complete"
done
# ==============> only for Master node
# kubeadm init --pod-network-cidr=172.66.0.0/16
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
# kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
# wget https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
# change 192.168.0.0 to 172.66.0.0
# kubectl apply -f calico.yaml
# kubectl taint nodes --all node-role.kubernetes.io/master-
# ==============> only for children node
# kubeadm join xxxxxxxxxxxxxxxxxxxxxxxxxx
- OK,该安装的都差不多了,这里再检查一下docker cgroup driver
docker info | grep -i cgroup
看下内容是不是cgroupfs就好
如果不是的话就运行
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl daemon-reload
- 此处可以保存一个快照等,用于后面安装差批了还可以修复
二、准备安装
- 刚才的环境复制3份,一共4个,一个master,3个node
名称分别是 node1-4
运行 hostnamectl set-hostname nodex
来设置hostname
如果想要方便一点就在 /etc/hosts
里面也设置上nodex和IP的对应关系
- 配置k8s Master节点
运行kubeadm init --pod-network-cidr=192.168.0.0/16
来初始化Master节点
192.168.0.0
其实是表示集群将使用Calico网络,所以提前指定了子网范围
命令运行完成后,会在输出中给出kubectl的配置方法,参考7.
同时输出的还有其他节点的加入方式,本例中输出如下
kubeadm join 192.168.86.134:6443 --token njvosm.9kg0zinc7wpbkcza \
--discovery-token-ca-cert-hash sha256:86dc3c622b8795a0fc77ff3d01efd64c40240316d27093b785ddedd880d799e2
具体的可选POD网络配置方式可以参考官网Pod Network
此处注意,--pod-network-cidr的IP范围并非是固定的,尤其是使用
kube-route
一类的pod network形式的时候,所以
- 根据kubeadm的输出,此时应运行以下命令来配置kubectl运行时配置,否则kubectl无法使用
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
- 运行
kubectl get pod -n kube-system
可以观察到以下效果,因为还没有配置具体Pod网络,所以CoreDNS是Pending
状态
kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-fb8b8dccf-c5s5d 0/1 Pending 0 2m28s
coredns-fb8b8dccf-l8z68 0/1 Pending 0 2m28s
etcd-node1 1/1 Running 0 90s
kube-apiserver-node1 1/1 Running 0 100s
kube-controller-manager-node1 1/1 Running 0 80s
kube-proxy-d9hhb 1/1 Running 0 2m29s
kube-scheduler-node1 1/1 Running 0 104s
- 根据官网的Pod Network章节,配置网络,本例中,应当运行
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
会有N多个image运行在Docker中,然后观察,就可以看到CoreDNS已经Running
了
kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-node-rj5r8 2/2 Running 0 71s
kube-system coredns-fb8b8dccf-c5s5d 1/1 Running 0 6m3s
kube-system coredns-fb8b8dccf-l8z68 1/1 Running 0 6m3s
kube-system etcd-node1 1/1 Running 0 5m5s
kube-system kube-apiserver-node1 1/1 Running 0 5m15s
kube-system kube-controller-manager-node1 1/1 Running 0 4m55s
kube-system kube-proxy-d9hhb 1/1 Running 0 6m4s
kube-system kube-scheduler-node1 1/1 Running 0 5m19s
- 默认情况下,Master节点是不会被调度管理器所管理的
但是不把Master算进去真的亏到哭,毕竟它是性能要求最高的一个(必须2h2g)
所以可以运行kubectl taint nodes --all node-role.kubernetes.io/master-
来把Master也加入到调度中,本质上是完成了一个Single-Node环境,minikube就是如此
饭店老板也一样给我出去端盘子
- 在其他节点上运行加入命令,查看效果
![jt1]
三、安装Web UI
- 这一步算是比较简单了,主要是参考官方文档
- 运行
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
,没啥问题的话就已经运行起来了 - 访问这块要注意一下,正常是通过
kubectl proxy
,然后localhost来访问,但是正常情况下这并不够
因为很多时候我们服务器是不带图形界面的,不能全通过localhost
所以此处需要加上几个参数,类似如下所示:
kubectl proxy --port=8080 --address=192.168.100.211 --accept-hosts='^192\.168\.100\.*'
其中port为指定监听端口,默认8001
address为监听地址,默认就是localhost,所以无法外面访问
accept-hosts必须要配置,否则访问会得到一个Forbidden
,可以写成'^*\.*\.*\.*'
来允许全部地址
- 然后就可以通过
http://address:port/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
来访问咯 - 如果发现了需要授权,或者什么码一类的才能访问,那么就可以参考此文档
四、配置Ingress来访问集群
- 集群对外的访问,有几种方式(都是通过service的方式暴露)
1> 通过Pod暴露
hostNetwork: true
的方式,此种方式用于“提前知道 特定IP下有特定端口的服务”的情况下,按照这种方式部署的pod的端口会直接通过pod宿主机上的所有网卡接口向外暴露,直接通过ip:port
就可以访问hostPort
方式,是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上hostPort
来访问 Pod 了,如:hostIP:hostPort
Port Forward
方式,通过kubectl port-forward
指令来实现数据转发的方法。该命令可以为 Pod 设置端口转发,通过在本机指定监听端口,访问这些端口的请求将会被转发到 Pod 的容器中对应的端口上。
2> 通过Serivce暴露
ClusterIP
方式,ClusterIP
是Service
的缺省类型,这种类型的服务会自动分配一个只能在集群内部可以访问的虚拟 IP,即:ClusterIP
。这种方式为你提供一个集群内部其它应用程序可以访问的服务,外部无法访问NodePort
方式,基于ClusterIP
提供的功能,为Service
在 Kubernetes 集群的每个节点上绑定一个端口,即 NodePort。集群外部可基于任何一个NodeIP:NodePort
的形式来访问 Service。Service 在每个节点的 NodePort 端口上都是可用的。LoadBalancer
方式,基于 NodePort 和云服务供应商提供的外部负载均衡器,通过这个外部负载均衡器将外部请求转发到各个 NodeIP:NodePort 以实现对外暴露服务
反正就是加了参数, hostNetwork: true,就运行起来了
6666
明天再写
五、在集群中配置ELK日志收集系统
- 一般来说,elasticsearch在运行时是有一些要求的,比如vm_map_max需要设置到多少等等,所以测试的时候用development模式就可以了,省事
- run 直接加env参数的方式要废弃了,用create又不能加参数,所以直接写成文件再
kubectl create -f file
- 先来创建一个elasticsearch单节点,走你
- 一般来说,正式环境下,我们的大部分操作都是通过
kubectl apply -f yamlfile
配合yaml文件来实现的,所以必须要学会yaml文件的编写才能更好的使用
下面记录一下deploy、service等文件的标准写法:
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: elasticsearch
labels:
app: elasticsearch
spec:
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: elasticsearch:7.0.1
env:
- name: discovery.type
value: single-node
###################################################
Service
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 80
###################################################
Multi-Port Service
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80 #cluster ip上的port,集群内部可以直接 cluster_ip:port访问的
targetPort: 9376 # 容器内部的port,比如nginx就是80,elasticsearch就是9200
- name: https
protocol: TCP
port: 443
targetPort: 9377
上面的
metadata.labels和spec.selector
和spec.template.metadata.labels
都是不可或缺的还有个奇怪的地方就是
spec.template.spec.containers
下面可以设置port,但是我并没看出来这个port
有什么意义
六、Bare-metal下的配置
如果在下载Docker的相关镜像的时候遇到卡顿问题,可以尝试使用DaoCloud的源来解决
对于国内环境而言,gcr.io是无法访问的,所以可以参考一下azk8s的相关配置
- 按照Docker官方文档来安装docker
- 安装kubeadm
- 配置kubeadm的源,如果是Debian系统,可以使用USTC的kubeadm源来安装,aliyun亦可
- 如果是CentOS,可以使用aliyun的镜像来安装
- 具体安装方式就参考官方文档,只不过要把里面的地址
https://apt.kubernetes.io/
或者https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
替换成国内源相应地址 - 对于Debian系列而言,如果没有从官方添加gpg验证文件,那么后面的apt-get命令就需要加上一个参数,如
apt-get --allow-unauthenticated update
- 安装
kubectl
kubeadm
kubelet
三基友
- 使用kubeadm来初始化Master节点
这一步的主要问题是,init命令所需的image,国内根本无法下载,所以需要使用镜像源,然而镜像源名字又不符合,所以还需要修改tag
还没有找到什么特别好的方法,只好一个个下载,然后一个个改tag了,还好用到的不算多
- 运行
kubeadm config images list
,列出所需要使用的image,将k8s.gcr.io
替换成gcr.azk8s.cn/google_containers/
,pull然后修改tag kubeadm init ......
什么的,可以开始初始化和让子节点来加入了
八、一点记录
- 本质上来讲,对内对外暴露的基础,就是service,因为pod的地址、节点等都会经常发生变化,所以pod自然不适合做为直接对外的暴露接口
- deploy是统治pod的上层接口,deploy如果不删除,那么Pod就会不断的创建
- 如果需要把deploy放到外面去,就必须抽调成service,用三种方式提供访问
- ingress也是基于service的
- 当B服务需要调用A服务时,可以给予它A的service名称作为IP地址,但是一定要保证两边的namespace相同
- service引用的本质其实是用的selector
- cidr的范围不能包括node的IP,否则会出现各种连接不上的问题
- 经过测试,kube-router好像不好用,所以还是用cali什么玩意的吧
- nodeSelector可以指定pod运行在哪个node上面,前提是已经给node打了标签
- 有时候遇到 未能识别的string错误啥的,就是指定的值被识别成别的东西了,比如 ·
n => "on"
就完事了 - hostAliases,可以给节点指定host文件的映射关系,需要放在 Deployment的 spec.template.spec下面,跟container 平级
- 下面是健康监测的实例
apiVersion: apps/v1
kind: Deployment
metadata:
name: tps-gateway-dtest
labels:
app: tps-gateway-dtest
spec:
selector:
matchLabels:
app: tps-gateway-dtest
template:
metadata:
labels:
app: tps-gateway-dtest
spec:
containers:
- name: tps-gateway-dtest
image: 10.13.32.168:5000/tps-gateway-dtest:201905291447
livenessProbe:
httpGet:
port: 8765
path: /actuator/health
initialDelaySeconds: 60
timeoutSeconds: 5 # when time out, kill our gateway
periodSeconds: 30 # repeat length
env:
- name: EUREKA_HOST
value: tps-center-dtest
- name: EUREKA_PORT
value: "8761"
volumeMounts:
- mountPath: /logs
name: logs-volume
volumes:
- name: logs-volume
hostPath:
path: /data/tps/logs
---
apiVersion: v1
kind: Service
metadata:
name: tps-gateway-dtest
spec:
selector:
app: tps-gateway-dtest
ports:
- protocol: TCP
port: 8765
targetPort: 8765
- 下面是一个hostAliases的实例
apiVersion: apps/v1
kind: Deployment
metadata:
name: tps-testcase-dtest
labels:
app: tps-testcase-dtest
spec:
selector:
matchLabels:
app: tps-testcase-dtest
template:
metadata:
labels:
app: tps-testcase-dtest
spec:
hostAliases:
- ip: "10.13.33.228"
hostnames:
- "test-gateway.itest.adc.com"
containers:
- name: tps-testcase-dtest
image: 10.13.32.168:5000/tps-testcase-dtest:201905291453
env:
- name: EUREKA_HOST
value: tps-center-dtest
- name: EUREKA_PORT
value: "8761"
- name: GATEWAY_HOST
value: tps-gateway-dtest
- name: GATEWAY_PORT
value: "8765"
volumeMounts:
- mountPath: /logs
name: logs-volume
volumes:
- name: logs-volume
hostPath:
path: /data/tps/logs
---
apiVersion: v1
kind: Service
metadata:
name: tps-testcase-dtest
spec:
selector:
app: tps-testcase-dtest
ports:
- protocol: TCP
port: 8771
targetPort: 8771