使用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暴露

  1. hostNetwork: true的方式,此种方式用于“提前知道 特定IP下有特定端口的服务”的情况下,按照这种方式部署的pod的端口会直接通过pod宿主机上的所有网卡接口向外暴露,直接通过 ip:port就可以访问
  2. hostPort方式,是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上 hostPort来访问 Pod 了,如: hostIP:hostPort
  3. Port Forward方式,通过kubectl port-forward指令来实现数据转发的方法。该命令可以为 Pod 设置端口转发,通过在本机指定监听端口,访问这些端口的请求将会被转发到 Pod 的容器中对应的端口上。

2> 通过Serivce暴露

  1. ClusterIP方式,ClusterIPService 的缺省类型,这种类型的服务会自动分配一个只能在集群内部可以访问的虚拟 IP,即:ClusterIP。这种方式为你提供一个集群内部其它应用程序可以访问的服务,外部无法访问
  2. NodePort方式,基于 ClusterIP 提供的功能,为 Service 在 Kubernetes 集群的每个节点上绑定一个端口,即 NodePort。集群外部可基于任何一个 NodeIP:NodePort 的形式来访问 Service。Service 在每个节点的 NodePort 端口上都是可用的。
  3. LoadBalancer方式,基于 NodePort 和云服务供应商提供的外部负载均衡器,通过这个外部负载均衡器将外部请求转发到各个 NodeIP:NodePort 以实现对外暴露服务
    lb

反正就是加了参数, 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.selectorspec.template.metadata.labels都是不可或缺的

还有个奇怪的地方就是spec.template.spec.containers下面可以设置port,但是我并没看出来这个port有什么意义

六、Bare-metal下的配置

如果在下载Docker的相关镜像的时候遇到卡顿问题,可以尝试使用DaoCloud的源来解决

对于国内环境而言,gcr.io是无法访问的,所以可以参考一下azk8s的相关配置

  1. 配置kubeadm的源,如果是Debian系统,可以使用USTC的kubeadm源来安装,aliyun亦可
  2. 如果是CentOS,可以使用aliyun的镜像来安装
  3. 具体安装方式就参考官方文档,只不过要把里面的地址https://apt.kubernetes.io/或者https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64替换成国内源相应地址
  4. 对于Debian系列而言,如果没有从官方添加gpg验证文件,那么后面的apt-get命令就需要加上一个参数,如apt-get --allow-unauthenticated update
  5. 安装kubectl kubeadm kubelet三基友
  • 使用kubeadm来初始化Master节点

这一步的主要问题是,init命令所需的image,国内根本无法下载,所以需要使用镜像源,然而镜像源名字又不符合,所以还需要修改tag

还没有找到什么特别好的方法,只好一个个下载,然后一个个改tag了,还好用到的不算多

  1. 运行kubeadm config images list,列出所需要使用的image,将k8s.gcr.io替换成gcr.azk8s.cn/google_containers/,pull然后修改tag
  2. 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

本文链接:

https://omen.ltd/archives/4/
1 + 4 =
快来做第一个评论的人吧~