Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k8s集群搭建及服务部署 #6

Open
MregXN opened this issue Jul 18, 2021 · 0 comments
Open

k8s集群搭建及服务部署 #6

MregXN opened this issue Jul 18, 2021 · 0 comments

Comments

@MregXN
Copy link
Owner

MregXN commented Jul 18, 2021

k8s集群搭建及服务部署

Kubernetes(k8s)是一个开源的容器集群管理装置,可以实现容器集群的自动化部署,自动化扩容缩容,维护等功能。本文将会记录在虚拟机上搭建k8s集群并部署应用的过程。

前置知识

组成

k8s集群会将机子按照功能分成两种:Control Plane, Node,功能和内部组件分别如下:

Control Plane

负责对集群做出全局决策,检测和响应集群事件,包括以下组件:

  • api server:作为control plane的前端暴露API供node使用。可以运行多个api server以平衡Node的流量

  • etcd:键值存储数据库,作为所有集群数据的后备存储

  • scheduler:为没有分配到node的pod分配node

  • controller manager:运行控制器进程

    包括node控制器(对node挂掉做出相应),job控制器(监视一次性任务的job对象,然后创建pod运行直至任务完成),endpoints控制器(填充endpoints对象到指定位置),service account & token 控制器(为新的命名空间创建默认账户和API访问令牌)

  • cloud controller manager:该组件允许用户将集群链接到云提供商的API。

Node

维护正在运行的pod并且提供kubernets运行的环境,包括以下组件:

  • kubelet:每个node运行一个kubelet,确保pod中的容器运行健康
  • kube-proxy:在每个node上运行的代理,用于实现集群内外部与pod之间的通信

一些概念

Namespace

Kubernetes支持由同一个物理集群支持多个虚拟集群。这些虚拟集群成为命名空间。

资源名称在一个命名空间内必须是唯一的,因此可以使用命名空间内在多个用户之间划分居群资源。

注意:Kubernetes的命名空间不能嵌套,每个资源只能在一个命名空间中

Pod

pod是可以在Kubernetes中创建和管理的最小的计算单元。其所建模的是一台特殊的逻辑主机,内部有一个或多个容器,这些容器共享存储,网络以及怎样运行这些容器的声明。用户可以使用工作负载资源来创建和管理多个pod。资源控制器能够处理副本的管理,上线,并在pod失效时提供自愈能力。

工作负载资源

工作负载是指在Kubernetes上运行的应用程序。工作负载资源指管理工作负载的方式,以下列举了部分可能用到的资源。

  • Deployments 为pods和ReplicaSets声明理想的运行状态 。

  • ReplicaSet 目的是保证一定数量的完全相同的pod的可用性。

  • DaemonSet 确保一定数量的节点上运行一个pod的副本。当有节点加入集群时会为他们新增pod,而当有节点移除时则回收该pod。删除daemonset会删除它创建的所有pod

    【与Deployments区别:它们都能创建 Pod,并且 Pod 中的进程都不希望被终止。建议为无状态的服务使用 Deployments,比如前端服务。 对这些服务而言,对副本的数量进行扩缩容、平滑升级,比精确控制 Pod 运行在某个主机上要重要得多。 当需要 Pod 副本总是运行在全部或特定主机上,并需要它们先于其他 Pod 启动时, 应该使用 DaemonSet。】

  • Job 负责批处理任务,即仅执行一次的任务。会创建一个或者多个 Pods,并将继续重试 Pods 的执行,直到指定数量的 Pods 成功终止。

  • ...

Service(服务)

服务指运行在一组pod上的应用程序公开的网络服务方法,通过选择算符实现(即查询标签)实现与pod的绑定。在集群中是一个REST对象,k8s会为服务分配一个虚拟IP。任何连接服务到请求,会首先访问iptables,内部的规则已经被kube-proxy改写,然后根据跳转规则代理到对应的pod中,一般通过轮转算法选择后端。

service在k8s中有四种类型:

  • ClusterIP:默认类型,自动分配一个集群IP,集群内部都可以访问
  • NodePort:绑定每一台Node的某个端口,可以通过<NodeIP>:端口号访问,通常需要在node外部再添加一个负载服务器
  • LoadBalance:在NodePort基础上借助云服务商的外部负载均衡器,将请求转发到<NodeIP>:端口号
  • ExternalName:把集群外部的服务引入到集群内部,没有代理被创建,需要填写外部IP及端口

service访问流程

网络模型?

k8s需要轻量地实现容器间的通信,pod间的通信,pod与服务的通信,以及内部与外部的通信。主要思路参考了docker:**让每个pod拥有一个IP,使得pod可以像虚拟机或者物理主机一样对待。**但是不应该使用NAT,因为NAT通过寻址空间引入了额外的复杂性,这样会破坏动态自注册的机制。

容器间通信: 一个pod中的所有容器的行为像是在同一台主机上,他们可以通过本地主机访问彼此的端口。几点好处:1.方便设置态端口;2.pod外部不可见,更安全 3.减少软件迁移的摩擦

pod间通信: 每个 Pod 获得一个唯一的 IP 地址, Pod 中的每个容器共享一个 IP 地址和端口空间,并且可以通过 localhost 发现对方。因为每个pod有自己的IP,因此pod可以在没有代理或者转换的情况下进行通信。当任何容器调用获取接口地址的方法时,看到的都是所属pod的IP地址。通过使pod内部和外部的IP地址+端口相同,可以创建一个无NAT的扁平的空间,而pod内部的容器通过卷或者IPC通信。

实现(以flannel为例):

通信过程:

通信过程:

同一主机的不同pod,走docker0网桥

不同主机的pod通信时会经过如图所示的流程,跨主机前会被Flanneld封装,数据包内同时包含pod子网IP以及NodeIP,通过UDP传送以此实现跨主机的扁平化网络。

职能:

  • 向etcd写入可以分配的子网网段

  • 监控每一个pod的地址(包括所在node的IP),并在内存中建立维护和pod节点的路由表

pod与服务间通信: 不同服务会对pod进行不同的分组。为了访问到对应的pod会创建一个虚拟IP,client访问该IP时会被透明地代理到服务中对应的pod。每个node都运行着k-proxy进程,该进程对iptables规则进行修改以捕获对服务IP的访问并将他们代理到对应的pod。

image-20210714095629182

外部与内部间通信: 目前的做法是设置外部均衡负载器(比如ingress),以集群中所有节点为目标。当流量到达节点时,该负载均衡器将这些流量也视为服务的一部分,并路由到特定的pod。但存在某些流量在网络内不断回弹的情况。

搭建准备

搭建准备

此次搭建准备了三台处于同一子网的虚拟机,操作系统是ubuntu20.04。约定192.168.137.71为Master,负责运行Control Plane,其余两台为Node。注意:虚机需要至少2*CPU核,并且关闭swap!

因为网络环境已经在墙外,后面的步骤将不会涉及类似配代理或更换源的步骤。

安装过程

1.Master安装Docker

sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y
sudo usermod -aG docker $USER

2.为集群设置hostname

# master
sudo hostnamectl set-hostname k8s-master
# Node1
sudo hostnamectl set-hostname k8s-slaveA
# Node2
sudo hostnamectl set-hostname k8s-slaveB

# 添加host解析
cat >> /etc/hosts <<EOF
192.168.137.71 k8s-master
192.168.137.122 k8s-slaveA
192.168.137.64 k8s-slaveB
EOF

# 互ping以测试修改是否成功
ping k8s-master
ping k8s-slaveA
ping k8s-slaveB

3.为集群配置iptables及内核

# 以下步骤在三台虚拟机都需要执行,主要是实现三台机子的转发机制
sudo iptables -P FORWARD ACCEPT

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF  

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

sudo sysctl --system

4. Master安装kubeadm kubelet kubbectl

sudo apt-get update
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

5.Master编辑配置文件

# 获得默认配置文件
kubeadm config print init-defaults > kubeadm.yaml

# 修改kubeadm.yaml
sudo vim kubeadm.yaml

# kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.137.71   #这里填写master的IP
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: k8s-master                   #这里填写master的hostname
  taints: null
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.21.0
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16          #这里设置pod的子网网段,使用flannel插件这样填写即可
  serviceSubnet: 10.96.0.0/12		
scheduler: {}

6.Master拉取镜像及初始化

kubeadm config images pull --config kubeadm.yaml
sudo kubeadm init --config kubeadm.yaml

初始化结束后,需要再复制配置文件,修改权限及添加node,根据提示操作即可。

7.安装Flannel插件

Kubernetes默认没有实现Pod虚拟IP的机制,因此需要安装其他插件。

# 获取lannel 配置文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 集群内安装并使用flannel
kubectl apply -f kube-flannel.yml

# 查看集群内是否建立成功。当coredns及flannel相关的pod都处于Running状态说明安装成功
kubectl get pod -n kube-system

补充:如果搭崩了需要重新来

  1. Node删除工作目录,重置kubeadm
sudo rm -rf /etc/kubernetes/*
kubeadm reset
  1. master 删除工作目录,并重置
sudo rm -rf /etc/kubernetes/* ~/.kube/* /var/lib/etcd/* /var/lib/etcd/o
kubeadm reset -f
  1. 从第6步的init指令开始继续

服务部署

1.配置Deployment

https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/)

# 直接部署官网示例的Deployment:拥有3份副本的nginx
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml

# 查看Deployment状态
kubectl get deployment

# 修改刚生成的Deployment,将行replicas的值由3改为4
kubectl edit deployment nginx-deployment

# 查看Deployment状态
kubectl get deployment

# 可以看到副本变成了四份
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   4/4     4            4           5d11h

2. 部署service

# kubectl expose --help  里面有句模板可以直接用
kubectl expose deployment nginx-deployment --port=80  --target-port=80

# 查看服务
kubectl get service  nginx-deployment  -o wide

# 可以看到该服务获得了一个虚拟的集群内IP,并打开了端口
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
nginx-deployment   ClusterIP   10.99.233.134   <none>        80/TCP    4d11h   app=nginx

# 任一机子尝试访问,可以收到nginx的默认页面,说明搭建成功
curl 10.99.233.134:80

3.Ingress暴露服务

# 安装Ingress控制器
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.48.1/deploy/static/provider/baremetal/deploy.yaml

# 查看Ingress控制器运行状态
kubectl get service -n ingress-nginx

# 可以看到Ingress暴露了随机端口,外部服务可以利用31817端口连接集群内的80端口
ingress-nginx-controller             NodePort    10.109.17.25   <none>        80:31817/TCP,443:30963/TCP   2d7h
ingress-nginx-controller-admission   ClusterIP   10.107.3.232   <none>        443/TCP                      2d7h

# 编辑Ingress配置文件
sudo vim ingress.yaml

# ingress.yaml填入以下内容
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: test.com                   # 这里的域名可以人为规定,Ingress根据域名访问不同的服务
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-deployment  # 访问上面的域名时会自动跳转到这里填写的服务
            port:
                    number: 80
                    
# 生效该配置文件
kubectl apply -f ingress.yaml 

# 查看Ingress状态
kubectl describe ingress

# 可以看到访问域名时,会被映射到4个后端pod
Name:             nginx-ingress
Namespace:        default
Address:          192.168.137.122
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host        Path  Backends
  ----        ----  --------
  test.com    
              /   nginx-deployment:80 (10.244.1.5:80,10.244.1.6:80,10.244.1.7:80 + 1 more...)
Annotations:  <none>
Events:       <none>

# 在主机上添加DNS解析规则:将C:\Windows\System32\drivers\etc\hosts内添加
192.168.137.122 test.com  #可以是任一虚拟机IP地址

# 利用浏览器访问 test.com:31817 ,可以看到nginx的默认页面,说明服务暴露成功

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant