.net core 微服务之 Kubernetes (K8s)

概念

什么是K8s

K8s : 容器编排引擎。是一个舵手,专门用来进行给docker掌管方向的,换句话说,就是用来控制docker运行容器的

K8s 就相当于上一篇文章当中的swarm。swarm是docker 自带的集群工具,相对K8s来说有很多不足

对比Swarm

Swarm优点(业务不是非常大,简单的情况)
 1、部署非常简单,架构简单,部署运维成本低
  swarm 命令搞定集群
 2、启动速度快
  内部只有2层交换,容器启动是毫秒级
缺点:
 1、无法提供精细化管理
  容器的管理
 2、网络问题
  在网络方面,默认docker容器是通过桥接与NAT和主机外网络通信,这样就出现2个问题,一个是因为是NAT,外部主机无法主动访问到容器内(除了端口映射),另外默认桥接IP是一样的,这样会出现不同主机的容器有相同的IP的情况。
  这样两容器更加不能通信。同时网络性能方面,有人测试经过桥接的网络性能只有主机网络性能的70%。当然以上问题可以通过其他工具解决,比如用 Flannel 或者 OVS网桥
 3、容器可靠性
  容器宕机了,无法重启
k8s优点(业务非常大,非常复杂的情况)
 1、提供精细化容器管理
  kubernetes 集群管理更趋于完善稳定,同时pod功能上比swarm的service更加强大
 2、健康监控机制
  Replication Controllers可以监控并维持容器的生命
 3、能够应对复杂的网络环境
  kubernetes默认使用Flannel作为overlay网络。
  Flannel是CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(OverlayNetwork)工具,其目的在于帮助每一个使用 Kuberentes 的CoreOS 主机拥有一个完整的子网。
缺点:
 1、配置,学习成本高
 2、启动很慢
   5层交互,启动是秒级

关于K8s

官方地址

https://kubernetes.io/zh/docs/tutorials/kubernetes-basics/

核心概念

 

kubeadm :k8s集群管理组件,管理集群,类型上一节中swarm

kubectl: 操作k8s集群客户端

kubelet:启动容器,运行每个节点容器,操作docker

搭建K8s

环境配置

有些版本要求服务器硬件至少2核2G的配置,为了使后面搭建成功,尽量满足这个要求

所有node节点都要执行1-9个步骤(第四个步骤只有master执行,node不执行)

1. 关闭防火墙

systemctl stop firewalld #防止端口不开发,k8s集群无法启动

2. 关闭selinux

setenforce 0 

可以根据命令 getenforce 获取状态

SELINUX=enforcing:强制模式,代表 SELinux 正常运行,所有的策略已经生效。(SELINUX的默认状态)
SELINUX=permissive:宽容模式,代表 SELinux 已经启动,但是只会显示警告信息,而并不会实际限制进程访问文件或目录资源。
SELINUX=disable:关闭,代表 SELinux 被禁用了。(修改指定的系统文件后,会达到此状态)。 

3. 关闭swap

类似于Windows的虚拟内存,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

它的功能就是在内存不够的情况下,操作系统先把内存中暂时不用的数据,存到硬盘的交换空间,腾出内存来让别的程序运行,和Windows的虚拟内存(pagefile.sys)的作用是一样的

swapoff -a    #临时关闭
free         # 可以通过这个命令查看swap是否关闭了,如果都显示0则已经关闭
vim /etc/fstab  永久关闭 注释swap那一行(访问内存分区,k8s无法启动)

4. 添加主机名与IP对应的关系,免密连接(这一步可以只在master执行

这一步我为后面传输网络做准备

  4.1 配置主机名与IP关系(我这里只有一个子节点)

vim /etc/hosts  
192.168.230.130 k8s-master 192.168.230.132 k8s-node1
...

  4.2 配置秘钥(一路按回车就行了)

ssh-keygen -t rsa

  4.3 配置好之后将秘钥复制到其他节点上面(期间需要输入其他节点主机的登录密码)

ssh-copy-id k8s-master   #自己也要执行一下
ssh-copy-id k8s-node1

配置完成之后可以连接测试一下

ssh k8s-node1  #也可以用IP

如果不需要输入密码就能连接,说明配置成功了(exit 退出当前远程连接)

5. 将桥接的IPV4流量传递到iptables 的链

cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

#这里也可以直接 vi /etc/sysctl.d/k8s.conf 去添加配置 

配置完后根据 sysctl --system 查看是否生效

6. 同步集群时间

centos7以下版本:

yum install ntpdate -y
ntpdate time.windows.com

centos7及以上版本:

yum -y install chrony              #新版本被chrony替代,安装chrony

vim  /etc/chrony.conf              #修改配置文件
      server cn.ntp.org.cn iburst #注释第一行,新增这一行 (server 需要同步的IP iburst) 

systemctl restart chronyd         #重启chrony    

systemctl status chronyd          #查看状态
 
systemctl start chronyd           #启动chrony   

chronyc sourcestats -v            #同步时间

timedatectl                       #查看是否同步成功

7. 添加阿里云YUM软件源

vim /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://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg #https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

8. 缓存索引,加快安装时间

centos7以下版本:

yum makecache fast

centos7及以上版本:

yum makecache 

9. 安装kubeadm,kubelet和kubectl

yum install -y kubectl-1.18.0 kubeadm-1.18.0 kubelet-1.18.0 --nogpgcheck

 检查是否成功

yum list installed |grep kube

 如果都安装成功,则显示如下

 

集群搭建

10. 初始化集群

kubeadm init --apiserver-advertise-address=192.168.230.130  --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.18.0 --service-cidr=10.1.0.0/16 --pod-network-cidr=10.244.0.0/16  



# --apiserver-advertise-address=192.168.230.130 #换成自己master的IP
# --pod-network-cidr 10.244.0.0/16 指定使用flanneld网络,使用flannel网络必须设置成这个cidr
#--kubernetes-version 指定Kubernetes版本
#--apiserver-advertise-address 指定apiserver的监听地址
#--apiserver-bind-port api-server 6443的端口
#--ignore-preflight-errors all 跳过之前已安装部分(出问题时,问题解决后加上继续运行)
# --pod-network-cidr 10.244.0.0/16 指定使用flanneld网络
 

 初始化话成功之后执行初始化结果返回的命令

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

查看节点状态,只有状态为Ready才叫初始化成功

kubectl get node

我这里为NotReady, 很明显失败了,排查一下原因。

这里通过kubectl get pods --all-namespaces 看一下状态发现前两个失败了,那就是需要安装flannel

这里来解决一下问题

# 安装flannel(在master执行)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 安装完flannel,将配置拷到node节点,否则添加节点之后状态不对。换成你的节点IP
scp -r /etc/cni root@192.168.230.132:/etc

# 这一步也要拷贝,否则节点看着正常,但是pod由于网络原因无法创建。换成你的节点IP
scp -r /run/flannel/ root@192.168.230.132:/run

执行之后再出初始化,这里由于之前初始化过,所以再次初始化要加   --ignore-preflight-errors all 跳过之前已安装部分(出问题时,问题解决后加上继续运行)

kubeadm init --apiserver-advertise-address=192.168.230.130  --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.18.0 --service-cidr=10.1.0.0/16 --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors all

最后看一下状态,发现已经变成了Ready了

 11. 创建node节点

第10步初始化成功之后和swarm一样,会生成一个一段命令,将这段命令复制在所有需要添加的node节点中执行,就能添加成功了

 

kubeadm join 192.168.230.130:6443 --token r4qk4s.tbz4kw6ui8hel9q6  --discovery-token-ca-cert-hash sha256:3b8ce3ea914a7e884ab2e6f355b2056a0e3b9c9eba642744d922b16466f8ec55

node节点执行成功之后会新增两个镜像

执行完,我们再在master中查看一下节点信息,发现已经加入一个节点信息了

节点中也可以执行 kubectl get nodes 查看节点信息,如果执行报错,则执行下面步骤

#在master 中执行,将larry改成你的节点名称
scp /etc/kubernetes/admin.conf root@larry:/etc/kubernetes/     


# 然后在node执行下面三步
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

master 如果中途发现问题 也可以重置

kubeadm reset

  重置之后重新初始化,重新初始化会发现很多问题,master中出现下面问题。

     正常情况下重新k8s可能也会出现上面问题。 kubctl执行操作的时候使用的kubernetes证书配置在/etc/kubernetes/admin.conf,应该是环境变量的问题。因为我们使用的root用户所以我直接使用的上面的命令配置的环境变量,但是这个是临时的,重启会失效。所以还是直接建个文件。

[root@JONI ~]# mkdir -p $HOME/.kube
[root@JONI ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
cp: overwrite '/root/.kube/config'? y
[root@JONI ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@JONI ~]# kubectl get node
NAME   STATUS   ROLES    AGE     VERSION
joni   Ready    master   7m41s   v1.18.0

 node也会因为之前加入过的master不存在,所以要先删除配置文件、证书信息、相应端口占用进程,最后初始化k8s

# 删除配置文件、证书信息、相应端口占用进程
[root@Larry ~]# rm -f /etc/kubernetes/kubelet.conf [root@Larry ~]# rm -f /etc/kubernetes/pki/ca.crt [root@Larry ~]# netstat -ntlup|grep 10250 tcp6 0 0 :::10250 :::* LISTEN 56903/kubelet [root@Larry ~]# kill -9 56903 # 下面执行初始化操作 [root@Larry ~]# swapoff -a [root@Larry ~]# kubeadm reset [reset] Reading configuration from the cluster... [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' W0207 15:06:32.147407 95488 reset.go:99] [reset] Unable to fetch the kubeadm-config ConfigMap from cluster: failed to get node registration: failed to get node name from kubelet config: open /etc/kubernetes/kubelet.conf: no such file or directory [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted. [reset] Are you sure you want to proceed? [y/N]: y [preflight] Running pre-flight checks W0207 15:06:35.595629 95488 removeetcdmember.go:79] [reset] No kubeadm config, using etcd pod spec to get data directory [reset] No etcd config found. Assuming external etcd [reset] Please, manually reset etcd to prevent further issues [reset] Stopping the kubelet service [reset] Unmounting mounted directories in "/var/lib/kubelet" [reset] Deleting contents of config directories: [/etc/kubernetes/manifests /etc/kubernetes/pki] [reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf] [reset] Deleting contents of stateful directories: [/var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni] The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d The reset process does not reset or clean up iptables rules or IPVS tables. If you wish to reset iptables, you must do so manually by using the "iptables" command. If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar) to reset your system's IPVS tables. The reset process does not clean your kubeconfig files and you must remove them manually. Please, check the contents of the $HOME/.kube/config file. [root@Larry ~]# systemctl daemon-reload [root@Larry ~]# systemctl restart kubelet [root@Larry ~]# iptables -F [root@Larry ~]# kubeadm join 192.168.230.130:6443 --token ptwqz4.7qpqh65f6op89758 --discovery-token-ca-cert-hash sha256:de4788814a6599716895c46c3f573f6a167af15316e4c821cc7a4c18f85150ea W0207 15:07:10.746864 95714 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set. [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/ [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 20.10.22. Latest validated version: 19.03 [WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service' [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

 

手动删除node。删除后重新加入节点,如果执行失败,就需要执行上面先删除配置文件、证书信息、相应端口占用进程,最后初始化k8s操作

kubectl delete node larry

操作K8S

环境搭建好了之后,认识一下pod,类似于swarm 中的service ,用来管理集群容器,一个pod可以装多个容器

 

kube-apiserver:接收 kubectl 命令

kube-controller-manager : 创建pod 

kube-scheduler : pod的调度员,将pod分发节点

kube-proxy :用来做负载均衡

  

简单运行pod

1. 运行pod,这个时候只是容器在pod内部使用,还不能给外界进行访问

kubectl run fcbnginx --image=nginx    #拉取远程nginx镜像
或者
kubectl run fcbpod --image=compose_fcbtest2 --image-pull-policy=IfNotPresent # 加上 --image-pull-policy=IfNotPresent 会拉取本地镜像

2. 查看pod列表

kubectl get pod

3. 查看指定pod相关信息,如果第二步显示状态异常也可以通过这个命令查看错误信息

kubectl describe pod fcbpod 

4. 上面只是在容器内部创建了pod,如果想要映射到外部访问,则通过expose创建service ,外部就能访问了

kubectl expose pod fcbpod --port=8080 --target-port=80 --type=NodePort

#--target-port=80 pod的端口号
#--port  pod映射到service的端口号,这里只是映射到service,不是外部访问的端口号,外部访问的端口是service再次随机映射的

5. 查看service

kubectl get service -o wide

 

这里的fcbpod就是我们新建的,可以看到PORT列中外部映射的端口号为32054,这里访问一下(master和node节点都能访问)

 

注:如果重启服务器之后出现  The connection to the server 192.168.230.130:6443 was refused - did you specify the right host or port?  ,重启一下kubectl 服务就可以了,node节点和master都要重启

[root@JONI ~]# kubectl get pod
The connection to the server 192.168.230.130:6443 was refused - did you specify the right host or port?
[root@JONI ~]# systemctl restart kubelet.service
[root@JONI ~]# kubectl get pod
NAME     READY   STATUS    RESTARTS   AGE
fcbpod   1/1     Running   0          7s

副本命令(伸缩命令)

一个deployment对应一个service,但是 可以包含多个pod

 1. 创建nginx副本deployment

kubectl create deployment nginx-deployment --image=nginx

2. 查看nginx副本deployment

kubectl get deployment -o wide

3. 暴露nginx副本deployment

kubectl expose deployment nginx-deployment --port=80 --target-port=8000 --type=NodePort

4. 查看暴露nginx副本deployment service

kubectl get service -o wide

5. 动态扩容nginx副本deployment

kubectl scale  --replicas=3 deployment/nginx-deployment
--replicas  扩容的数量(pod总共的数量,方便做负载均衡扩容)


yaml文件部署本地.net core web项目

这里镜像就用上面测试的 compose_fcbtest2 本地镜像。主要是要添加批处理文件,配置部分说明

#### nginx副本集部署deployment

apiVersion: apps/v1 #k8s版本号
kind: Deployment #部署类型(资源类型)
metadata: #元数据(用于定义资源信息)
  name: nginx-deployment-tony5 #资源名称
  labels: #资源标签(版本号)
    app: nginx 
spec: #资源相关信息规范
  replicas: 3 #副本数
  selector: #选择哪一个版本
    matchLabels:
      app: nginx
  template: #模板
    metadata: #资源的元数据/属性
      labels: #设置资源的标签
        app: nginx
    spec: #资源规范字段(规范容器配置)
      containers: #指定容器
      - name: nginx #容器名称
        image: nginx #容器使用的镜像
        ports: #端口号
        - containerPort: 80 #容器对应的端口号
```

#### nginx暴露service

apiVersion: v1 # 指定api版本,此值必须在kubectl api-versions中
kind: Service # 指定创建资源的角色/类型
metadata: # 资源的元数据/属性
  name: service-tony # 资源的名字,在同一个namespace中必须唯一
  namespace: default # 部署在哪个namespace中
  labels: # 设定资源的标签
    app: demo
spec: # 资源规范字段
  type: NodePort # ClusterIP 类型
  ports:
    - port: 8080 # service 端口
      targetPort: 80 # 容器暴露的端口
      protocol: TCP # 协议
      name: http # 端口名称
  selector: # 选择器(选择什么资源进行发布给外界进行访问:pod deployment 等等资源)
    app: nginx
```

更多说明可以参考网上这篇文章 

1. 创建一个yaml文件,我这里随便取名叫 fcbtest2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fcbtestpod
  labels:
    k8s-app: fcbtestpod
spec:
  replicas: 2
  selector:
    matchLabels:
      k8s-app: fcbtestpod
  template:
    metadata:
      labels:
        k8s-app: fcbtestpod
    spec:
      containers:
      - name: fcbtestpod
        image: compose_fcbtest2
        imagePullPolicy: Never
        ports:
        - containerPort: 80
---
kind: Service
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: fcbtestpod
  name: fcbtestservice
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    k8s-app: fcbtestpod

2. 执行一下 就完成了

kubectl create -f fcbtest2.yaml

3. 运行检查一下

[root@JONI k8syaml]# kubectl get pod,svc -o wide
NAME                                    READY   STATUS    RESTARTS   AGE     IP              NODE    NOMINATED NODE   READINESS GATES
pod/fcbtestpod-bcfc895d4-c7bgs          1/1     Running   0          17m     10.244.32.218   larry   <none>           <none>
pod/fcbtestpod-bcfc895d4-kl5cm          1/1     Running   0          17m     10.244.32.217   larry   <none>           <none>
pod/nginx-deployment-5969c7f455-6vl2c   1/1     Running   0          5h47m   10.244.32.208   larry   <none>           <none>
pod/nginx-deployment-5969c7f455-7vfwp   1/1     Running   0          6h2m    10.244.32.204   larry   <none>           <none>
pod/nginx-deployment-5969c7f455-8ts4h   1/1     Running   0          5h47m   10.244.32.207   larry   <none>           <none>
pod/nginx-deployment-5969c7f455-lkb62   1/1     Running   0          6h      10.244.32.206   larry   <none>           <none>
pod/nginx-deployment-5969c7f455-skgmz   1/1     Running   0          6h      10.244.32.205   larry   <none>           <none>

NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE    SELECTOR
service/fcbtestservice     NodePort    10.1.22.69     <none>        80:31192/TCP   17m    k8s-app=fcbtestpod
service/kubernetes         ClusterIP   10.1.0.1       <none>        443/TCP        3d1h   <none>
service/nginx-deployment   NodePort    10.1.207.174   <none>        80:32179/TCP   6h1m   app=nginx-deployment

浏览器访问

 

 4. 查看系统日志

# 查看最后两百行的日志
kubectl logs --tail 200 pod名称/service名称
# 查看最后两百行的日志,持续输出
kubectl logs -f --tail 200 pod名称/service名称
# 返回pod 标记为 k8s-app=fcbtestpod (service对应的selector名称)最近200行的日志
kubectl logs --tail 200 -l k8s-app=fcbtestpod     
#查看最近一小时日志
kubectl logs --since=1h pod名称
或者
kubectl logs --since=1h -l service对应的selector名称

Docker 四种 网络类型

可以查看网上这篇文章

1. bridge 桥接

 docker服务默认会创建一个docker0网桥,该桥接网络的名称是docker0,它是内核层连通了其他物理或虚拟网卡,这就是将所有容器和本地主机都放到同一个物理的网络中。docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通讯。可以看做一个网段,一个项目用同一个bridge,项目中包含多个微服务。

 2. host 主机

直接使用宿主机的ip地址与外界进行通信,不再需要额外进行NAT转换。如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

 3. none

Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

 4. container

这个模式指定新创建的容器和引进存在的一个容器共享一个network namespect ,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的ip,而是和一个指定的容器共享ip,端口等,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信

posted @ 2023-02-15 16:27  Joni是只狗  阅读(611)  评论(2编辑  收藏  举报