05-k8s

一、概述

二、安装及配置

  1. 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
  1. 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
setenforce 0 # 临时
  1. 关闭swap分区
swapoff -a # 临时
vim /etc/fstab # 永久
  1. 设置主机名字
hostnamectl set-hostname <hostname>
  1. 在 master 添加 hosts(三台主机)
cat >> /etc/hosts << EOF
192.168.227.20 master
192.168.227.21 node1
192.168.227.22 node2
EOF
  1. 将桥接的 IPv4 流量传递到 iptables 的链(三台主机)
cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

sysctl --system
  1. 时间统部
yum install ntpdate -y
ntpdate time.windows.com
  1. 所有节点安装 Docker/kubeadm/kubelet

(1)安装 Docker

# 依赖安装
yum install -y yum-utils device-mapper-persistent-data lvm2
# 阿里源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# docker
yum install docker-ce -y   # 安装指定版本,例如yum install -y docker-ce-18.09
systemctl start docker
systemctl enable docker

(2)设置阿里云 YUM 软件源

cat > /etc/docker/daemon.json << EOF
{
	"registry-mirrors": ["https://qtaqfn8r.mirror.aliyuncs.com"],
    "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
systemctl restart docker
# 添加yum源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[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
EOF

(3)安装 kubeadm,kubelet 和 kubectl

yum install -y kubelet-1.16.2 kubeadm-1.16.2 kubectl-1.16.2

systemctl start kubelet
systemctl enable kubelet
  1. 部署 Kubernetes Master

(1)在 192.168.227.20(Master)执行

kubeadm init   --apiserver-advertise-address=192.168.227.20 --image-repository registry.aliyuncs.com/google_containers   --kubernetes-version v1.23.0   --service-cidr=10.140.0.0/16 --pod-network-cidr=10.240.0.0/16
  • 由于默认拉取镜像地址 k8s.gcr.io 国内无法访问,这里指定阿里云镜像仓库地址。

(2)使用 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 nodes
  1. 加入 Kubernetes Node

(1)在 192.168.31.62/63(Node)执行

向集群添加新节点,执行在 kubeadm init 输出的 kubeadm join 命令:

kubeadm join 192.168.227.20:6443 --token esce21.q6hetwm8si29qxwn \
--discovery-token-ca-cert-hash
sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5
  1. 安装 Pod 网络插件(CNI)

注意:这里的yml文件有问题,需要手动创建文件并切换ip

# 下载文件
wget https://github.com/xuwei777/xw_yaml/blob/main/kube-flannel.yml
# 修改net-conf.json下面的网段为上面init pod-network-cidr的网段地址(必须正确否则会导致集群网络问题)
sed -i 's/10.244.0.0/10.240.0.0/' kube-flannel.yml
kubectl apply –f kube-flannel.yml
# 查看插件进度
kubectl get pods -n kube-system
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp.flannel.unprivileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
    seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
    apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
    apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
  privileged: false
  volumes:
  - configMap
  - secret
  - emptyDir
  - hostPath
  allowedHostPaths:
  - pathPrefix: "/etc/cni/net.d"
  - pathPrefix: "/etc/kube-flannel"
  - pathPrefix: "/run/flannel"
  readOnlyRootFilesystem: false
  runAsUser:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  allowPrivilegeEscalation: false
  defaultAllowPrivilegeEscalation: false
  allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
  defaultAddCapabilities: []
  requiredDropCapabilities: []
  hostPID: false
  hostIPC: false
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  seLinux:
    rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: flannel
rules:
- apiGroups: ['extensions']
  resources: ['podsecuritypolicies']
  verbs: ['use']
  resourceNames: ['psp.flannel.unprivileged']
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      hostNetwork: true
      priorityClassName: system-node-critical
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni-plugin
        image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0
        command:
        - cp
        args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        volumeMounts:
        - name: cni-plugin
          mountPath: /opt/cni/bin
      - name: install-cni
        image: rancher/mirrored-flannelcni-flannel:v0.18.1
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: rancher/mirrored-flannelcni-flannel:v0.18.1
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
        - name: xtables-lock
          mountPath: /run/xtables.lock
      volumes:
      - name: run
        hostPath:
          path: /run/flannel
      - name: cni-plugin
        hostPath:
          path: /opt/cni/bin
      - name: cni
        hostPath:
          path: /etc/cni/net.d
      - name: flannel-cfg
        configMap:
          name: kube-flannel-cfg
      - name: xtables-lock
        hostPath:
          path: /run/xtables.lock
          type: FileOrCreate
  1. 测试 k8s 集群

在 Kubernetes 集群中创建一个 pod,验证是否正常运行:

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看pod状态,必须是running状态而且ready是1,并查看nginx svc的80端口映射到了哪个端口
kubectl get pod,svc
  • 访问地址:http://NodeIP:Port

安装kuboard图形管理平台

在K8S集群之外准备一台主机安装docker,并通过docker安装kuboard

[root@kuboard ~]# yum -y install yum-utils
[root@kuboard ~]# yum-config-manager --add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/dockerce.repo
[root@kuboard ~]# yum -y install docker-ce-20.10.9-3.el7
[root@kuboard ~]# systemctl enable --now docker
创建kuboard
[root@kuboard ~]# docker run -id --name=kuboard --restart=always -p 80:80 -p 10081:10081 -e KUBOARD_ENDPOINT="http://192.168.0.26:80" -e KUBOARD_AGENT_SERVER_TCP_PORT="10081" -v /root/kuboard-data:/data eipwork/kuboard:v3
  • 访问kuboard页面:http://server_ip

三、资源管理方式

kubernetes的本质就是一个容器集群统一管理系统,用户可以在集群中部署各种服务,所谓部署服务就是在kubernetes集群中运行一个一个的容器,并将指定的程序跑在容器中

在kubernetes中,所有内容都被抽象为资源对象,学习kubernetes主要学习如何管理资源对象

# 所有资源可通过下面命令进行查看
kubectl api-resources

1、K8s资源类型介绍

资源名称缩写资源作用
nodesno集群组成部分
namespacesns隔离pod
podspo,pod装载容器(容器组)
replicationcontrollersrc控制pod资源
replicasetsrs控制pod资源
deploymentsdeploy控制pod资源
daemonsetsds控制pod资源
jobs控制pod资源
cronjobscj控制pod资源
horizontalpodautoscalershpa控制pod资源
statefulsetssts控制pod资源
servicessvc统一pod对外接口
ingressing统一pod对外接口
volumeattachments存储资源
persistentvolumespv存储资源
persistentvolumeclaimspvc存储资源
confifigmapscm配置资源
secrets配置资源
serviceaccountsa服务账户
  • 直接使用kubectl命令去管理k8s集群
kubectl run nginx-pod --image=nginx:1.17.4 --port=80
  • 将配置写入到yaml文件,通过文件去管理k8s集群
kubectl create/patch -f nginx-pod.yaml

是kubernetes集群的命令行工具,通过它能过够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。

# 获取命令帮助
kubectl --help

2、常用指令

命令作用
create 创建一个资源
edit编辑一个资源
get获取一个资源
patch更新一个资源
delete删除一个资源
explain展示资源文档
run在命令行运行一个容器
expose在命令行暴露资源端口
describe显示资源内部信息
logs输出容器在pod中的日志
exec进入运行中的容器
cp在pod内外复制文件
rollout管理资源的发布
scale扩(缩)容pod的数量
autoscale自动调整pod的数量
apply创建资源/更新资源
label标签管理命令
cluster-info显示集群信息
version显示当前Server和Client版本信息

**命令格式:**kubectl [command] [type] [name] [flags]

  • command:指定要对资源执行的操作,例如:create、get、delete
  • type:指定资源类型,例如:deployment、pod、service
  • name:指定资源名称,名称区分大小写
  • flags:指定额外的可选参数,例如:-o wide

练习

资源名称缩写资源作用
podspo装载容器
#查看所有pod
kubectl get pod

#查看指定的pod(根据pod名字查找)
kubectl get pod nginx-696649f6f9-g5nds

#查看指定pod,通过额外参数显示pod详细信息,包括pod的IP地址,pod运行的节点等
kubectl get pod nginx-696649f6f9-g5nds -o wide

#查看指定pod,通过额外参数显示pod信息,以json格式显示
kubectl get pod nginx-696649f6f9-g5nds -o json

#查看指定pod,通过额外参数显示pod信息,以yaml格式显示
kubectl get pod nginx-696649f6f9-g5nds -o yaml

#显示指定pod资源内部信息
kubectl describe pod nginx-696649f6f9-g5nds

#显示当前Server和Client版本信息
kubectl version

#显示集群信息
kubectl cluster-info

四、Namespace名命空间

Namespace(名称空间)是kubernetes系统中的一种非常重要的资源,它的主要作用是用来实现资源隔离(例如生活中的房间)可以将不同的Pod划分到不同的Namespace(名称空间)进行隔离,可以形成逻辑上的“组”

案例:以一个namespace(名称空间)的创建和删除简单演示命令用法

资源名称缩写资源作用
namespacesns隔离pod
查看ns信息
# kubectl get ns
calico-apiserver calico 网络资源命名空间
calico-system calico 网络资源命名空间
default 默认的名称空间,所有未指定的Pod都会被分配在该空间下
kube-node-lease 集群节点之间的心跳维护
kube-public 该名称空间下的资源可以被所有人访问,包括未认证的用户
kube-system 所有由k8s系统创建的核心组件资源都处于这个名称空间
tigera-operator calico 网络资源名称空间查看指定ns的信息

# kubectl get pod -n kube-system
创建一个名为dev的ns
# kubectl create ns dev
# kubectl get ns
删除ns
# kubectl delete ns dev

1、yaml

特点

  • 严格区分大小写
  • 使用缩进表示层级关系
  • 缩进不允许使用tab键,只允许使用空格,缩进的空格数量没有严格要求,只要相同层级左对齐即可
  • # 号表示注释
  • 书写YAML切记 : 后边要加一个空格
  • 如果需要将多段YAML配置放在同一个文件中,中间需要用 — 作为分格

2、yaml常见数据结构

  • 对象(Object):键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表 (list)

对象类型:对象的一组键值对,使用冒号结构表示

#对象形式一(推荐)
个人信息:
    name: zhangsan
    age: 30
    address: tianjin
#对象形式二(了解)
个人信息: {name: zhangsan,age: 30,address: tianjin}

数组类型:一组连词线开头的行,构成一个数组

- 联系方式:
  phone: 138****6789
  QQ:
  WeChat:
  emal:

复合结构:对象和数组可以结合使用,形成复合结构

个人信息:
  name: zhangsan
  age: 30
  address: tianjin
  - 联系方式:
    phone:
    QQ:
    WeChat:
    emal:

3、k8s资源对象描述

在kubernetes中基本所有资源的一级属性都是一样的,主要分为五部分:

  • apiVersion:资源版本,由k8s内部定义,版本号必须可以通过kubectlapi-versions 查询到
  • kind:资源类型,由k8s内部定义,类型必须可以通过kubectl api-resources查询到
  • metadata:元数据,主要是指定资源标识与说明,常用的有name、namespace、labels等
  • spec:资源描述,这是配置中最重要的一部分,里边对各种资源配置的详细描述
  • status:资源状态信息,里边的内容不需要定义,有k8s自动生成

4、yaml文件创建资源

案例:通过yaml文件创建一个test命名空间

kubect explain 资源名称 #explain用于查看资源文档

查看ns文档:kubectl explain ns

查看子属性:kubectl explain ns.metadata

# vim ns_test.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test
执行文件创建ns
# kubectl create -f ns_test.yaml

查看ns信息
# kubectl get ns
test

通过yaml文件删除ns
# kubectl delete -f ns_test.yaml

五、Pod

1、概述

  • Pod 是 k8s 系统中可以创建和管理的最小单元

    Pod(碗豆菜)是kubernetes集群进行管理的最小单元,程序必须部署在容器中,而容器必须存在于Pod中,kubernetes集群启动以后,集群中的各个组件也都是以Pod方式运行。

  • 包括多个容器(一组容器的集合)

  • 一个pod中容器共享网络命名空间。

  • pod是短暂的(每次重启都会改变ip

1.1、Pod特性

  1. 资源共享

    一个 Pod 里的多个容器可以共享存储和网络,可以看作一个逻辑的主机。共享的如namespace,cgroups 或者其他的隔离资源。

    多个容器共享同一 network namespace,由此在一个 Pod 里的多个容器共享 Pod 的 IP 和端口namespace,所以一个 Pod 内的多个容器之间可以通过 localhost 来进行通信,所需要注意的是不同容器要注意不要有端口冲突即可。不同的 Pod 有不同的 IP,不同 Pod 内的多个容器之前通信,不可以使用 IPC(如果没有特殊指定的话)通信,通常情况下使用 Pod的 IP 进行通信。

    一个 Pod 里的多个容器可以共享存储卷,这个存储卷会被定义为 Pod 的一部分,并且可以挂载到该 Pod 里的所有容器的文件系统上。

  2. 生命周期短暂

    Pod 属于生命周期比较短暂的组件,比如,当 Pod 所在节点发生故障,那么该节点上的 Pod会被调度到其他节点,但需要注意的是,被重新调度的 Pod 是一个全新的 Pod,跟之前的Pod 没有半毛钱关系。

  3. 平坦的网络

    K8s 集群中的所有 Pod 都在同一个共享网络地址空间中,也就是说每个 Pod 都可以通过其他 Pod 的 IP 地址来实现访问。

1.2、存在的意义

  1. 创建容器使用docker,一个docker对应一个容器,一个容器有进程,一个容器运行一个应用程序

  2. Pod是多进程设计,运行多个应用程序

    一个Pod有多个容器,一个容器里面运行一个应用程序

  3. Pod存在为了亲密性应用

    1. 两个应用之间进行交互
    2. 网络之间调用
    3. 两个应用需要频繁调用

2、实现机制

每一个 Pod 都有一个特殊的被称为根容器的 Pause容器。Pause 容器对应的镜 像属于 Kubernetes 平台的一部分,除了 Pause 容器,每个 Pod还包含一个或多个紧密相关的用户业务容器

  • 共享网络:通过Pause容器,把其他业务容器加入到Pause容器里面,让所有业务容器在同一个名称空间中,可以实现网络共享
  • 共享存储:引入数据卷概念Volumes,使用数据卷进行持久话存储
image-20230719110243335
image-20230719110553952
image-20230719110609821

3、细节

3.1、imagePullPolicy

  • IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
  • Alawys:总是从远程仓库拉取镜像
  • Never:只使用本地镜像,从不去远程仓库拉取,本地如果没有就报错
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
[root@master ~]# kubectl explain pod.spec.containers.imagePullPolicy

3.2、resources

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
创建pod
# kubectl create -f deploy_nginx.yml

查看pod信息
# kubectl get pod -n test

查看pod详细描述信息
# kubectl describe pod -n test 

删除deploy
# kubectl delete -f deploy_nginx.yml

3.3、restartPolicy

容器一旦出现了问题,K8s就会对容器所在的pod进行重启,重启操作是由pod的重启策略决定的,pod的重启策略有三种,可通过下边命令查看

  • Always:当容器终止退出后,总是重启容器,默认策略
  • OnFailure:当容器异常退出(推出状态码非0)时,才重启容器。
  • Never:当容器终止推出,从不重启容器
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
[root@master ~]# kubectl explain pod.spec.restartPolicy

重启策略适用于pod中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作延时时长为10s、20s、40s、80s、160s、300s,最长延时为300s,以后重启延时均为300s,直至重启成功

5、调度策略

5.1、pod创建过程

  1. kubectl将yaml文件转换为json,提交给apiserver,apiserver通过kubeconfig进行认证,将Pod信息存储到etcd

  2. scheduler通过list watch机制监听到创建新Pod的事件,根据Pod属性决定调度到哪个Node上,Pod属性包括请求的CPU/内存大小nodeSelector亲和性污点容忍等,同时给Pod打标签指明调度到具体哪个节点,可以通过kubectl get pod -owide查看

  3. apiserver拿到调度结果并写入到etcd中

  4. kubelet从apiserver获取分配到其所在节点的Pod

  5. kubelet调用CNI接口创建Pod网络,调用CSI进行存储卷挂载,调用CRI接口启动容器

  6. Docker把容器的状态汇报给kubelet

  7. kubelet将Pod状态更新到apiserver,apiserver将状态信息写到etcd中

  8. kubectl get pod

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.2、资源限制和节点选择器

  1. 资源限制影响Pod调度
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  1. 节点选择器标签影响Pod调度
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3、亲和性

  1. 硬亲和性

    约束条件必须满足

  2. 软亲和性

    尝试满足,不保证

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.4、污点和污点容忍

污点殊值有三个

  1. NoSchedule:一定不会被调度
  2. PreferNoSchdule:尽量不被调度
  3. NoExecute:不会调度,并且还会驱逐Node已有Pod
kubectl taint node [node] key=value:污点三个值

六、Pod控制器

在k8s中,pod的创建方式分为两类:

  1. 静态Pod: 也称之为无控制器管理的自主式pod,直接由特定节点上的kubelet 守护进程管理, 不需要API 服务器看到它们,对于静态 Pod 而言,kubelet 直接监控每个 Pod,这种pod删除后就没有了,也不会重建。
  2. 控制器管理的pod: 控制器可以控制pod的副本数,扩容与缩容版本更新版本回滚等。

k8s的1.17之前版本中, kubectl run命令默认通过Deployment控制器创建Pod,在v1.18版本中, kubectl run命令改为创建静态pod

pod控制器是管理pod的中间层,使用了pod控制器之后,我们只需要告诉pod控制器,需要多少个什么样的pod就可以了,它就会创建出满足条件的pod,并确保每一个pod处于用户期望的状态,如果pod在运行中出现故障,控制器会基于指定的策略重新启动重建pod

在k8s中,pod控制器的种类有很多,每种pod控制器的应用场景都不一样,常见的有下面这些:

  • ReplicationController:比较原始的pod控制器,目前已经被废弃,由ReplicaSet代替。

  • ReplicaSet:支持pod数量变更,镜像版本变更

  • Deployment(无状态):通过ReplicaSet来控制pod,包含ReplicaSet所有功能,还支持滚动升级版本回退

    微服务就是无状态的一种

滚动:当有新版本的镜像,会替换掉最初的版本。如果有三个镜像需要升级,则会先替换掉一个。

  • Horizontal Pod Autoscaler:可以根据集群负载自动调整pod数量,实现pod扩容缩

  • DaemonSet:节点级别控制器,确保全部每一个节点上运行一个 Pod的副本,当有 Node 加入集群时,也会为他们新增一个 Pod ,当有Node 从集群移除时,这些 Pod 也会被回收,删除 DaemonSet 将会删除它创建的所有 Pod。

    收集所有主机的日志

  • StatefulSet:StatefulSet 是用来管理有状态的应用,例如数据库。

    所谓的有状态Mysql就是具有存储能力,如果服务器死了,其他服务器拉取数据还是在的,有一个稳定的域名

  • Job:运行一次性任务的Pod,它创建的pod只要完成就立即退出(健康检查,数据备份)。

容器按照持续运行的时间可分为两类:服务类容器和工作类容器

  • 服务类容器通常持续提供服务,需要一直运行,比如http、server、daemon 等

  • 工作类容器则是一次性任务,比如批处理程序,完成后容器就退出

  • Cronjob:它创建的pod会周期性的执行,用于执行周期性任务(常用在数据备份工作)。

1、Pod资源清单介绍

以下是比较详细的资源清单介绍

KIND: Pod #资源类型类型
VERSION: v1 #资源版本
DESCRIPTION: #资源描述
FIELDS: #资源可配置的属性,如下

apiVersion: v1 #必选的一级属性,版本号,例如v1
kind: Pod #必选的一级属性,资源类型,例如Pod
metadata: #必选的一级属性,元数据
  name: #必选的二级属性,Pod名称
  namespace: dev #二级属性,Pod所属的名称空间,例如dev,默认为default名称空间
  labels: #二级属性,自定义标签列表
  - name: #三级属性,标签名称
  
spec: #必选的一级属性,Pod中容器的详细定义
  containers: #必选的二级属性,Pod中容器列表
  - name: #必选的三级属性,容器名称
    image: #必选的三级属性,容器镜像名称
    imagePullPolicy: #三级属性,镜像的拉取策略
    command: #三级属性,容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: #三级属性,容器的启动命令参数列表
    workingDir: #三级属性,容器的工作目录
    volumeMounts: #三级属性,挂载到容器内部的存储卷配置
    - name: #四级属性,引用pod定义的共享存储卷的名称
      mountPath: #四级属性,存储卷在容器内mount的绝对路径,应少于512字节
      readOnly: #四级属性,是否为只读模式
    ports: #三级属性,需要暴露的端口库号列表
    - name: #四级属性,端口的名称
      containerPort: #四级属性,容器需要监听的端口号
      hostPort: #四级属性,容器所在的主机需要监听的端口号,默认与Container相同
      protocol: #四级属性,端口协议,支持TCP/UDP,默认为TCP
    env: #三级属性,容器运行前需要设置的环境变量列表
    - name: #四级属性,环境变量名称
      value: #四级属性,环境变量的值
    resources: #三级属性,资源限制和请求的设置
      limits: #四级属性,资源最大限制的设置
      CPU: #五级属性,CPU资源限制,单位为core数,将用于docker run --cpu-shares参数
      memory: #五级属性,内存资源限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests: #四级属性,资源最小请求的设置
        CPU: #五级属性,CPU请求,容器启动的初始可用数量
	    memory: #五级属性,内存请求,容器启动的初始可用数量
    lifecycle: #三级属性,生命周期钩子
      postStart: #四级属性,容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
      preStop: #四级属性,容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe: #三级属性,对Pod内个容器健康检查设置,当探测容器无响应后将自动重启该容器
    tcpSocket: #三级属性,对Pod内容器健康检查方式
    initialDelaySeconds: #三级属性,容器启动完成后,首次探测时间,单位为秒
    timeoutSeconds: #三级属性,对容器健康检查探测等待相应的超时时间,单位秒,默认1秒
    periodSeconds: #三级属性,对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
  restartPolicy: #二级属性,Pod的重启策略
  nodeName: #二级属性,设置pod调度到指定的node节点上
  nodeSelector: #二级属性,设置Pod调度到指定的label的node节点上
  imagePullSecrets: #二级属性,拉取镜像时,使用secret名称,以key:secretkey格式指定
  hostNetwork: #二级属性,是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
  volumes: #二级属性,在该Pod上定义共享存储卷列表
    - name: #三级属性,共享存储卷名称
    emptyDir: #三级属性,类型为emptyDir的存储卷,与Pod同生命周期的一个临时目录,为空值
    hostPath: #三级属性,类型为hostPath的存储卷,挂载集群与定义的secret对象到容器内部
      path: #四级属性,Pod所在宿主机的目录,将被用于容器中挂载的目录
    secret: #三级属性,类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
    configMap: #三级属性,类型为configMap的存储卷,挂载预定义的configMap对象到容器内部

2、控制器 ReplicaSet(RS)

2.1、ReplicaSet(RS)特点介绍

ReplicaSet的主要作用是保证一定数量的pod能够正常的运行,它会持续监听这些pod的运行状态,一旦pod发生故障,就会重启重建pod,同时还支持对pod数量的扩缩容版本镜像变更

ReplicaSet的资源清单文件查询方式

kubectl explain rs
kubectl explain rs.spec
kubectl explain rs.spec.selector
kubectl explain rs.spec.template
kubectl explain rs.spec.template.metadata
kubectl explain rs.spec.template.spec

2.2、ReplicaSet(RS)应用案例

案例:通过RS控制器创建3个Nginx Pod

# vim rs_nginx.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-nginx
  namespace: test
spec:
  replicas: 3 #创建pod的副本数量,默认为1
  selector: #标签选择器,通过它指定RS管理哪些pod
    matchLabels: #标签类型(key=value)
      app: rs-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板,通过模板创建Pod
    metadata: #定义模板的元数据信息
      labels: #定义Pod的标签
        app: rs-nginx #Pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.0
        
创建pod
# kubectl create -f rs_nginx.yml
查看pod详细信息
# kubectl get pod -n test
过滤Pod标签
# kubectl describe pod -n test | grep Labels
查看pod控制器详细信息
# kubectl get rs -n test -o wide

DESIRED:期望的pod副本数量
CURRENT:当前的pod副本数量
READY:已经准备好提供服务的副本数量

8.3、ReplicaSet(RS)版本变更

案例:通过RS控制器实现镜像版本变更

通过edit(配置文件形式)可直接修改镜像版本
# kubectl edit rs rs-nginx -n test
...
  spec:
    containers:
    - image: nginx:1.18.0 #修改为1.18.0版本查看rs详细信息
    
# kubectl get rs -n test -o wide

删除RS方式

命令删除方式
# kubectl delete rs rs-nginx -n test

查看rs信息
# kubectl get rs -n test

配置文件删除方式
# kubectl delete -f rs-nginx.yml

3、控制器 Deployment

为了更好的解决服务编排问题,k8s在v1.2版本开始,引入了Deployment(Deploy)控制器,该pod控制器不会去直接管理pod,而是通过管理ReplicaSet来间接的管理pod,所以Deployment比ReplicaSet功能更强大

**Deployment功能如下 **

  • 支持RS所有功能
  • 支持发布的停止、继续
  • 支持版本滚动更新和版本回退

导出yaml文件

kubectl create deployment web --image=nginx --dry-run -o yaml > web.yaml

案例:通过deploy创建基本的pod

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 3 #创建pod的副本数量,默认为1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.0

创建deploy
# kubectl create -f deplo_nginx.yml
查看deploy详细信息
# kubectl get deploy -n test
# kubectl get deploy -n test -o wide
UP-TO-DATE:最新版本的pod数量
AVAILABLE:当前可用的pod数量

查看rs控制器信息,应为deploy通过控制rs管理pod,所以rs控制器也会被创建出来(rs的名称在deploy基础上随机添加)
# kubectl get rs -n test
查看pod信息(pod名称是在rs基础上随机添加)
# kubectl get pod -n test
过滤Pod标签
# kubectl describe pod -n test | grep Labels
删除deploy
# kubectl delete -f deploy_nginx.yml

4、多容器创建方式

案例:将nginx与tomcat放在同一个Pod中运行

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: test
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
      
  template:
    metadata:
     labels:
      app: deploy-nginx
      
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: web-nginx
          containerPort: 80
          protocol: "TCP"
        resources:
          limits: #资源上限
            cpu: "500m" #500m表示0.5个逻辑核心,1000m表示一个逻辑核心
            memory: "128Mi" #内存单位可以使用Gi、Mi、G、M等形式
          requests: #资源下限
            cpu: "250m" #250m表示0.25个逻辑核心,
            memory: "64Mi" #所需最低内存资源(如果不足64M,容器无法启动)
          
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        imagePullPolicy: IfNotPresent
        ports:
        - name: web-tomcat
          containerPort: 8080
          protocol: "TCP"
        resources:
          limits: #资源上限
            cpu: "500m" #500m表示0.5个逻辑核心,1000m表示一个逻辑核心
            memory: "128Mi" #内存单位可以使用Gi、Mi、G、M等形式
          requests: #资源下限
            cpu: "250m" #250m表示0.25个逻辑核心,
            memory: "64Mi" #所需最低内存资源(如果不足64M,容器无法启动)创建Pod
            
# kubectl create -f deploy_nginx.yml
查看Pod信息
# kubectl get pod -n test
删除该Pod
# kubectl delete -f deploy_nginx.yml

5、env

evn属性是用于设置容器环境变量的列表,环境变量的定义要根据容器具体需求定义,本章节只讲解如何定义环境变量

可通过下方命令获取env文档帮助
# kubectl explain pod.spec.containers.env
name 定义环境变量名称
value 定义变量值

案例:为MySQL添加环境变量设置root密码

# vim pod_mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-mysql
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-mysql #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-mysql #pod的标签
    spec:
      containers:
      - name: mysql
        image: mysql:5.7 #镜像版本
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义端口
        - containerPort: 3306 #端口
          protocol: TCP #端口协议
        env: #定义环境变量
        - name: "MYSQL_ROOT_PASSWORD" #变量名称(必须为数组类型)
          value: "123456" #值创建Pod
          
# kubectl create -f pod_mysql.yml
查看Pod信息
# kubectl get pod -n test
查看Pod详细描述
# kubectl describe pod -n test

6、exec

  • 格式:kubectl exec -n 命名空间 -it pod名称 -c 容器名称 -- /bin/bash

kubectl exec -h #命令帮助

案例:进入上述案例中创建的mysql容器

# kubectl exec -n test -it deploy-nginx-579696c576-jfqz6 -c mysql -- /bin/bash
进入数据库
root@deploy-nginx-579696c576-jfqz6:/# mysql -uroot - p123456

案例:进入上述案例中创建的nginx容器

# kubectl exec -n test -it deploy-nginx-579696c576-jfqz6 -c nginx -- /bin/bash

查看网页根目录
root@deploy-nginx-579696c576-jfqz6:/# ls /usr/share/nginx

7、Pod容器执行命令方式

格式:kubectl exec pod名 -c 容器名 -- 命令

注意:

  • -c 容器名为可选项,如果是1个pod中1个容器,则不用指定;
  • 如果是1个pod中多个容器,不指定默认为第1个。
# kubectl exec nginx-deployment-5fc678675d-5w8c2 -n test -c nginx -- ls /etc/nginx
# kubectl exec nginx-deployment-5fc678675d-5w8c2 -n test -c nginx -- cat /etc/nginx/nginx.conf

删除deploy

kubectl delete -f deploy_nginx.yml

8、Pod调度

定向调度

在默认情况下,一个pod被调度到哪个Node节点运行是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的,但是在实际工作中,我们想要控制某些pod调度到指定的Node节点,就需要用到pod调度

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

k8s提供了四种调度方式

  • 自动调度:pod运行在哪个Node节点上,完全由Scheduler经过算法分配(默认的调度策略)
  • 定向调度:NodeName、NodeSelector
  • 亲和性调度与反亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污点(容忍)调度:Taints、Toleration
NodeName

定向调度是通过在pod上声明NodeName或者NodeSelector,以此将pod调度到指定的节点上,但是定向调度属于强制调度,即使指定的Node节点不存在,也会向该节点进行调度,只不过pod运行失败而已

定向调度方式其实是直接跳过了Scheduler的调度逻辑,直接将pod调度到指定名称的节点

案例:创建pod,并通过NodeName将Pod调度到worker01节点

kubectl explain pod.spec.nodeName

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      nodeName: worker01 --定义调度策略,并指定worker01节点
      containers:
      - name: nginx
        image: nginx:1.20.0 #指定一个本地不存的镜像版本
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义端口
        - containerPort: 80 #端口
          protocol: TCP #端口协议
          
创建pod
# kubectl create -f deploy_nginx.yml
查看pod详细信息
# kubectl get pod -n test -o wide
删除deploy
NodeSelector

nodeSelector用于将pod调度到添加了指定标签的node节点上,该调度规则也是强制调度

案例:先为worker02节点打标签,然后创建一个pod,并通过nodeSelector进行调度

为node1与node2节点打标签
# kubectl label node worker02 node=worker02
查看节点标签
# kubectl get node worker02 --show-labels | grep worker02
创建Pod并通过NodeSelector进行调度
# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
  spec:
    nodeSelector: 定义nodeSelector
      node: worker02 指定节点标签
    containers:
    - name: nginx
      image: nginx:1.20.0 #指定一个本地不存的镜像版本
      imagePullPolicy: IfNotPresent #镜像拉取策略
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议创建pod
        
# kubectl create -f deploy_nginx.yml
查看pod详细信息
# kubectl get pod -n test
# kubectl get pod -n test -o wide
删除deploy
# kubectl delete -f deploy_nginx.yml

污点 Taint

前面的调度方式都是站在pod的角度上,通过在pod上添加属性,来确定pod是否要调度到指定的node上,其实我们也可以站在node的角度上,通过在node上添加污点属性,来决定是否允许pod调度过来

node被设置上污点以后,就和pod之间存在了一种相互排斥的关系,进而拒绝pod调度进来,甚至可以将已经存在的pod驱逐出去

污点的格式:key:污点,key和value是污点的标签,目前支持如下三个污点:

  • PreferNoSchedule:尽量避免调度(软限制),除非没有其他节点可调度
  • NoSchedule:拒绝调度(硬限制),但不会影响当前已经存在的pod
  • NoExecute:拒绝调度,同时也会将节点上已经存在的pod清除(尽量不要设置,会导致Pod异常)

提示:如果通过定向调度的方式去创建Pod,那么定向调度的优先级要高于污点。

也就是说不管你有没有污点,只要我通过定向调度的方式,就可以直接忽略你污点的存在

使用kubectl设置和去除污点的命令实例如下:

设置污点
kubectl taint nodes worker01 key:污点
去除污点
kubectl taint nodes worker01 key:污点-
去除所有污点
kubectl taint nodes worker01 key-
PreferNoSchedule

为worker01设置污点,名称为:worker01:PreferNoSchedule

[root@master01 ~]# kubectl taint node noed1 node1:PreferNoSchedule

查看污点信息
[root@master01 ~]# kubectl describe node worker01 | grep Taints
Taints: worker01:PreferNoSchedule

# 创建Pod验证
[root@master01 ~]# kubectl create -f deploy_nginx.yml
# 查看Pod所在节点健康状态
[root@master01 ~]# kubectl get pod -n test -o wide
# 删除deploy
[root@master01 ~]# kubectl delete -f deploy_nginx.yml
# 删除PreferNoSchedule污点
[root@master01 ~]# kubectl taint node worker01 worker01:PreferNoSchedule-
NoSchedule

设置worker01污点为:worker01:NoSchedule

[root@master01 ~]# kubectl taint node worker01 worker01:NoSchedule
查看污点信息
[root@master01 ~]# kubectl describe node worker01 | grep Taints
Taints: worker01:NoSchedule
创建Pod
[root@master01 ~]# kubectl create -f deploy_nginx.yml
查看Pod所在节点健康状态
[root@master01 ~]# kubectl get pod -n test -o wide
#提示:可以发现当前的pod状态为Pending(挂起状态)
删除deploy
[root@master01 ~]# kubectl delete -f deploy_nginx.yml

提示:使用k8s搭建的集群,会默认给master节点添加一个NoSchedule污点,所以pod不能被调度到master节点中

容忍 Toleration

上章节讲解了污点的作用,可以通过在worker节点添加污点用于拒绝pod调度上来,但如果我们非要将一个pod调度到一个有污点的node上,通过容忍(忽略污点)可以实现

容忍的配置项说明:

可通过下边命令查看容器的配置项
# kubectl explain pod.spec.tolerations
effect 容忍的污点
key 容忍的污点的key

案例:继上述案例,创建pod并添加容忍,然后将pod调度到worker01节点

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      imagePullPolicy: IfNotPresent #镜像拉取策略
      tolerations: 添加容忍
      - key: "worker01" 污点的key(必须引起来)
        effect: NoSchedule 污点类型
      containers:
      - name: nginx
        image: nginx:1.17.0 #指定镜像
        ports: #定义端口
        - containerPort: 80 #端口
          protocol: TCP #端口协议
        
创建pod
# kubectl create -f deploy_nginx.yml
查看pod详细信息
# kubectl describe pod -n test
删除deploy并删除yaml文件中的容忍配置项
# kubectl delete -f deploy_nginx.yml
删除污点
# kubectl taint node worker01 worker01:NoSchedule-

Pod或者ns出现异常,可以尝试通过下边的方式进行删除

# kubectl delete pod pod名称 -n ns名称 --force --grace-period=0

亲和性 affinity

  • nodeAffinity(node亲和性):以Node为目标,解决Pod可以调度到那些Node的问题。
  • podAffinity(pod亲和性):以Pod为目标,解决Pod可以和那些已存在的Pod部署在同一个拓扑域中的问题。
  • podAntiAffinity(pod反亲和性):以Pod为目标,解决Pod不能和那些已经存在的Pod部署在同一拓扑域中的问题。

关于亲和性和反亲和性的使用场景的说明:

  • 亲和性:如果两个应用频繁交互,那么就有必要利用亲和性让两个应用尽可能的靠近,这样可以较少因网络通信而带来的性能损耗。

  • 反亲和性:当应用采用多副本部署的时候,那么就有必要利用反亲和性让各个应用实例打散分布在各个Node上,这样可以提高服务的高可用性。

nodeAffinity
  • 查看nodeAffinity的可选配置项:
pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution  Node节点必须满足指定的所有规则才可以,相当于硬限制
    nodeSelectorTerms  节点选择列表
      matchFields   按节点字段列出的节点选择器要求列表  
      matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)     
    preference   一个节点选择器项,与相应的权重相关联
      matchFields 按节点字段列出的节点选择器要求列表
      matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
        key 键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt  
    weight 倾向权重,在范围1-100。

关系符的使用说明:

- matchExpressions:
	- key: nodeenv # 匹配存在标签的key为nodeenv的节点
	  operator: Exists   
	- key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
	  operator: In    
      values: ["xxx","yyy"]
    - key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点
      operator: Gt   
      values: "xxx"
  • 下面演示requiredDuringSchedulingIgnoredDuringExecution(硬限制):
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      requiredDuringSchedulingIgnoredDuringExecution: # Node节点必须满足指定的所有规则才可以,相当于硬规则,类似于定向调度
        nodeSelectorTerms: # 节点选择列表
          - matchExpressions:
              - key: nodeenv # 匹配存在标签的key为nodeenv的节点,并且value是"xxx"或"yyy"的节点
                operator: In
                values:
                  - "xxx"
                  - "yyy"
  • 创建pod
kubectl create -f pod-nodeaffinity-required.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 查看Pod状态(运行失败):
kubectl get pod pod-nodeaffinity-required -n dev -o wide
  • 查看Pod详情(发现调度失败,提示node选择失败):
kubectl describe pod pod-nodeaffinity-required -n dev

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 删除pod
kubectl delete -f pod-nodeaffinity-required.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 修改pod-nodeaffinity-required.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      requiredDuringSchedulingIgnoredDuringExecution: # Node节点必须满足指定的所有规则才可以,相当于硬规则,类似于定向调度
        nodeSelectorTerms: # 节点选择列表
          - matchExpressions:
              - key: nodeenv # 匹配存在标签的key为nodeenv的节点,并且value是"xxx"或"yyy"的节点
                operator: In
                values:
                  - "pro"
                  - "yyy"
  • 查看pod
kubectl get pod pod-nodeaffinity-required -n dev -o wide

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

nodeAffinity的注意事项:

  • 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都满足,Pod才能运行在指定的Node上。

  • 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可。

  • 如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有的才能匹配成功。

  • 如果一个Pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的nodeAffinity的要求,则系统将忽略此变化。

podAffinity
  • podAffinity主要实现以运行的Pod为参照,实现让新创建的Pod和参照的Pod在一个区域的功能。

  • PodAffinity的可选配置项:

pod.spec.affinity.podAffinity
  requiredDuringSchedulingIgnoredDuringExecution  硬限制
    namespaces 指定参照pod的namespace
    topologyKey 指定调度作用域
    labelSelector 标签选择器
      matchExpressions  按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist.
      matchLabels    指多个matchExpressions映射的内容  
  preferredDuringSchedulingIgnoredDuringExecution 软限制    
    podAffinityTerm  选项
      namespaces
      topologyKey
      labelSelector
         matchExpressions 
            key    键  
            values 值  
            operator
         matchLabels 
    weight 倾向权重,在范围1-1

topologyKey用于指定调度的作用域,例如:

  • 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围。

  • 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。

  • 演示requiredDuringSchedulingIgnoredDuringExecution。

  • 创建参照Pod过程:

    • 创建pod-podaffinity-target.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: dev
  labels:
    podenv: pro # 设置标签
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  nodeName: k8s-node1 # 将目标pod定向调度到k8s-node1
    • 创建参照Pod:
kubectl create -f pod-podaffinity-target.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 查看参照Pod:
kubectl get pod pod-podaffinity-target -n dev -o wide

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 创建Pod过程:

    • 创建pod-podaffinity-requred.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAffinity: # Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: # 该Pod必须和拥有标签podenv=xxx或者podenv=yyy的Pod在同一个Node上,显然没有这样的Pod
              - key: podenv
                operator: In
                values:
                  - "xxx"
                  - "yyy"
          topologyKey: kubernetes.io/hostname
    • 创建Pod:
kubectl create -f pod-podaffinity-requred.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 查看Pod状态,发现没有运行:
kubectl get pod pod-podaffinity-requred -n dev

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 查看Pod详情:
kubectl get pod pod-podaffinity-requred -n dev

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 删除Pod:
kubectl delete -f pod-podaffinity-requred.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 修改pod-podaffinity-requred.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAffinity: # Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: # 该Pod必须和拥有标签podenv=xxx或者podenv=yyy的Pod在同一个Node上,显然没有这样的Pod
              - key: podenv
                operator: In
                values:
                  - "pro"
                  - "yyy"
          topologyKey: kubernetes.io/hostname
    • 再次创建Pod:
kubectl create -f pod-podaffinity-requred.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 再次查看Pod:
kubectl get pod pod-podaffinity-requred -n dev -o wide

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

podAntiAffinity(反亲和性)
  • podAntiAffinity主要实现以运行的Pod为参照,让新创建的Pod和参照的Pod不在一个区域的功能。

  • 其配置方式和podAffinity一样,此处不做详细解释。

  • 使用上个案例中的目标Pod:

kubectl get pod -n dev -o wide

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 创建pod-podantiaffinity-requred.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAntiAffinity: # Pod反亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions:
              - key: podenv
                operator: In
                values:
                  - "pro"
          topologyKey: kubernetes.io/hostname
  • 创建Pod:
kubectl create -f pod-podantiaffinity-requred.yaml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 查看Pod:
kubectl get pod -n dev -o wide

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

11、Probe

容器探测类似于对容器进行健康检查,用来探测容器中的程序是否可以正常工作,如果探测到容器出现故障,k8s会尝试重启容器,如果重启失败,k8s不会将流量分配给该容器,不承担业务流量。

k8s提供了两种探针来实现容器的探测,可通过下边命令查看:

  • livenessProbe :存活性探针,用于检测容器当前是否处于正常运行状态,如果不是,容器将会被重启。
  • readinessProbe:就绪性探针,用于检测容器当前是否可以接收请求,如果不能,k8s不会转发流量。
# kubectl explain pod.spec.containers

以上两种探针目前均支持多种探测方式,可通过下边命令查看:

# kubectl explain pod.spec.containers.livenessProbe
# kubectl explain pod.spec.containers.readinessProbe
# 存活探针
FIELDS:
exec 命令探测方式
tcpSocket 端口探测方式
httpGet URL请求探测方式
# 就绪探针
initialDelaySeconds 容器启动后等待多少秒执行第一次探测
timeoutSeconds 探测超时时间,默认1秒,最小可设置1秒
failureThreshold 连续探测失败多少次才被认定失败,默认3次为失败,最小可设置1
periodSeconds 执行探测频率,默认是10秒,最小可设置1秒
successThreshold 连续探测成功多少次才被认定为成功,默认1次

以livenessProbe存活性探针给大家介绍两种常用的探测方式:

exec

方式一:exec命令探测方式,在容器内执行一次命令,如果命令执行的退出码为0,则认位程序正常,否则不正常。

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
  spec:
    containers:
    - name: nginx
      image: nginx:1.18.0 #镜像版本
      imagePullPolicy: IfNotPresent #镜像拉取策略
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议
      livenessProbe: 存活性探针
        exec: 命令探测方式
          command: [/bin/ls,/etc/hello.txt] 探测一个不存在的文件
创建Pod
# kubectl create -f deploy_nginx.yml
查看Pod信息
# kubectl get pod -n test
查看Pod详细信息
# kubectl describe pod -n test
删除deploy
# kubectl delete -f deploy_nginx.yml

探测一个存在的文件
# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
  spec:
    containers:
    - name: nginx
      image: nginx:1.18.0 #镜像版本
      imagePullPolicy: IfNotPresent #镜像拉取策略
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议
      livenessProbe: 存活性探针
        exec: 命令探测方式
          command: [/bin/ls,/usr/share/nginx/html/index.html] 探测一个存在的文件
          
创建Pod
# kubectl create -f deploy_nginx.yml
查看Pod详细信息
# kubectl describe pod -n test
删除Deploy
# kubectl delete -f deploy_nginx.yml

tcpSocket

==方式2:==tcpSocket端口探测方式,访问容器的端口,如果能够建立连接,则认位程序正常,否则不正常。

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
  spec:
    containers:
    - name: nginx
      image: nginx:1.18.0 #镜像版本
      imagePullPolicy: IfNotPresent #镜像拉取策略
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议
      livenessProbe: 存活性探针
        tcpSocket: 端口探测方式
          port: 8080 探测一个不存在的端口
提示:删除前边的探测方式,探测方式不能指定超过2种类型
创建pod
# kubectl create -f deploy_nginx.yml
查看pod描述信息
# kubectl describe pod -n test
...
Liveness probe failed: dial tcp 10.244.1.10:8080: connect: connection refused
#提示:活性探针失败,8080拒绝连接
删除deploy
# kubectl delete -f deploy_nginx.yml
探测一个存在的端口
# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
  spec:
    containers:
    - name: nginx
      image: nginx:1.18.0 #镜像版本
      imagePullPolicy: IfNotPresent #镜像拉取策略
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议
      livenessProbe: 存活性探针
        tcpSocket: 端口探测方式
          port: 80 探测一个存在的端口
创建pod
# kubectl create -f deploy_nginx.yml
查看pod详细信息
# kubectl describe -f deploy_nginx.yml
删除deploy
# kubectl delete -f deploy_nginx.yml

livenessProbe和readinessProbe区别

livenessProbereadinessProbe 是 Kubernetes 中用于健康检查的两种属性。尽管它们可以使用相同的 tcpSocket 属性来检查容器的健康状态,但是它们的主要目的和使用方式有所不同。

  1. livenessProbe 属性:用于确定容器是否处于运行状态。通过定期向容器发送请求,并检查响应状态码或响应时间,来确定容器是否正常运行。如果 livenessProbe 失败,则 Kubernetes 认为容器出现了问题,并会触发重启策略以尝试修复容器。
  2. readinessProbe 属性:用于确定容器是否已经准备好接收流量。通过定期向容器发送请求,并检查响应状态码或响应时间,来确定容器是否就绪并可接受流量。如果 readinessProbe 失败,则 Kubernetes 认为容器尚未准备好处理流量,并将从 Service 的负载均衡中排除该容器

虽然 tcpSocket 可以在 livenessProbereadinessProbe 中使用,但是它们的使用场景和目的是不同的。如果您将 tcpSocket 用作 livenessProbe,那将仅仅检查容器是否处于运行状态,不关心容器是否已经准备好处理流量。这意味着即使容器已经启动并且正在监听端口,但是如果容器的内部服务或应用程序尚未准备好接受流量,它仍然会被视为健康的,并且可能会接收到流量

因此,为了更精确地控制容器的行为和避免不可预料的问题,建议在需要时同时使用 livenessProbereadinessProbe。通过使用适当的请求路径、端口和其他检查参数,可以更全面地确保容器的完整性、可用性和可靠性,并正确控制容器的生命周期和流量管理。

13、strategy

在 Kubernetes 中,Deployment 资源对象具有一个 strategy 字段,用于定义其更新策略。该字段包含以下两个子字段:

  1. type:指定更新策略的类型,可选的值有:
    • Recreate:在进行更新时先将旧的 Pod 删除,然后创建新的 Pod。这种策略会导致短暂的应用中断,因为在删除和创建过程中会存在一段时间的空窗期。
    • RollingUpdate:采用滚动更新的方式进行更新,逐步替换旧的 Pod。这是默认的更新策略。
  2. rollingUpdate:仅在 type 字段设置为 RollingUpdate 时才需要配置。它指定了滚动更新的行为,包含以下子字段:
    • maxUnavailable:指定在进行滚动更新时最多允许不可用的 Pod 的数量或百分比。
    • maxSurge:指定在进行滚动更新时额外允许创建的 Pod 的数量或百分比。

Recreate

案例:通过Recreate对Pod进行重建更新

修改deploy_nginx.yml文件设置Pod更新策略
# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  strategy:    #Pod更新策略
    type: Recreate #重建更新
  replicas: 3 #指定Pod数量
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
    app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent #镜像拉取策略
        ports: #定义端口
        - containerPort: 80 #端口
          protocol: TCP #端口协议
创建pod
# kubectl create -f deploy_nginx.yml
另外开一个终端动态观察pod的信息
# kubectl get pod -n test -w
更新镜像版本
# kubectl edit deploy deploy-nginx -n test
...
spec:
  containers:
    - image: nginx:1.18.1 指定新版本
提示:观察pod的重建过程
#第一步:将Running的pod先终止(Terminating)
#第二步:接下来Pod处于等待状态(Pending)
#第三步:重新创建容器(ContainerCreating)
#第四步:新的容器被创建且以成功运行(Running )
查看镜像版本
# kubectl get deploy -n test -o wide
删除depoly
# kubectl delete -f deploy_nginx.yml

RollingUpdate

案例:通过RollingUpdat对Pod进行滚动更新(默认策略,无需指定,只需要将前边配置文件中的其他更新策略删除即可)

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  strategy:
  type: RollingUpdate 滚动更新
  rollingUpdate:
    maxUnavailable: 1 指定在进行滚动更新时最多允许不可用的Pod的数量或百分比。
    maxSurge: 1 指定在进行滚动更新时额外允许创建的Pod的数量或百分比。
  replicas: 6
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
   template: #pod的配置模板
     metadata:
       labels:
         app: deploy-nginx #pod的标签
   spec:
     containers:
     - name: nginx
       image: nginx:1.18.1
       imagePullPolicy: IfNotPresent #镜像拉取策略
       ports: #定义端口
       - containerPort: 80 #端口
         protocol: TCP #端口协议
         
创建pod(--record 记录整个deploy更新历史)
# kubectl create -f deploy_nginx.yml --record
另外一个终端动态查看pod信息
# kubectl get pod -n test -w
更新镜像版本
# kubectl edit deploy deploy-nginx -n test
spec:
  containers:
    - image: nginx:1.20.0
查看RS信息
# kubectl get rs -n test -o wide
提示:当pod滚动更新后,rs也会随之跟着更新,原有rs中的pod会被删除,但
是原有的rs并不会删除,用于做版本回退
显示当前升级版本的状态
# kubectl rollout status deploy deploy-nginx -n test

14、rollout

Deploy支持版本升级过程中的暂停、继续、回退等功能,具体功能如下:kubectl rollout 版本升级相关功能,支持下面的选项:

  • status #显示当前升级状态

  • history #显示升级历史记录

  • pause #暂停版本升级过程

  • resume #继续已经暂停的版本升级过程

  • restart #重启版本升级过程

  • undo #回滚到上一级版本(可以通过–to-revision回滚到指定版 本)

案例:多次更新镜像版本,随后对镜像版本进行回退

更新镜像版本
# kubectl edit deploy deploy-nginx -n test
spec:
  containers:
    - image: nginx:1.20.1
更新镜像版本
# kubectl edit deploy deploy-nginx -n test
spec:
  containers:
    - image: nginx:1.21.0
查看升级历史记录
# kubectl rollout history deploy deploy-nginx -n test
查看具体版本详细信息:--revision=版本编号
# kubectl rollout history deploy deploy-nginx --revision=2 -n test
查看当前所有版本(通过rs可以查看)
# kubectl get rs -o wide -n test
查看当前使用版本(查看deploy)
# kubectl get deploy -o wide -n test
版本回退:通过--to-revision=1,可直接回滚到1版本,如果省略这个选项,就是回退到上个版本
# kubectl rollout undo deploy deploy-nginx --to-revision=2 -n test
查看当前使用的版本
# kubectl get deploy -o wide -n test
查看升级历史记录
# kubectl rollout history deploy deploy-nginx -n test
提示:新版本就是原先的1版本

提示:如果不指定回退版本默认会回到上一个版本

15、控制器 DaemonSet

DaemonSet(DS)控制器在功能方面与Deployment控制器几乎一样,支持滚动更新版本回退等,只不过它在创建Pod时,可以保障集群中的每一个节点(master)上都运行(Pod数量与节点数量保持一致)。

如果一个pod提供的功能是节点级别的(每个节点都需要且只需要一个),一般适用于日志收集节点监控场景,这种类型的pod就适合使用DaemonSet类型的控制器创建

DaemonSet控制器的特点:

  • 每当像集群添加一个节点时,指定的pod副本也将添加到该节点上
  • 当节点从集群中移除时,pod也就被垃圾回收

案例:通过daemonset控制器创建Nginx Pod,并保证在每个节点都运行。

# vim ds_nginx.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      name: ds-nginx
  template:
    metadata:
      labels:
        name: ds-nginx
    spec:
      tolerations: # 添加容忍,否则pod无法被调度到master节点
      - key: node-role.kubernetes.io/master # 污点key
        effect: NoSchedule # 污点类型
      containers:
        - name: nginx
          image: nginx:1.18.0
          ports:
          - containerPort: 80
          
创建pod
# kubectl create -f ds_nginx.yml
查看ds信息
# kubectl get ds -n test
查看pod详细信息
# kubectl get pod -n test -o wide
删除ds
# kubectl delete -f ds_nginx.yml

16、控制器 HPA

Horizontal Pod Autoscaler(HPA)可以实现pod数量的自动扩缩容,对比于前边手动对pod数量进行调整,HPA更加的智能。

HPA可以获取每个pod的资源利用率,然后和HPA中定义的资源利用率指标进行对比,同时计算出需要伸缩的具体值,最后实现pod的数量的自动(非手动)调整。

metrics-server资源监控

Metrics-Server是集群核心监控数据的监视器,用于采集节点的CPU和内存资源,从 Kubernetes1.8 开始用来替换之前的heapster,heapster从1.11开始逐渐被废弃。

安装metrics-server可以用来收集集群中的资源使用情况(已经下载,拷贝到主机即可)

[root@master01 ~]# wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
文件内容需要修改
#vim components.yaml
...
  - args:
    - --kubelet-insecure-tls 添加该参数忽略证书检测
创建metrics-server
[root@master01 ~]# kubectl create -f components.yaml
查看metrics-server运行状态
[root@master01 ~]# kubectl get pod -n kube-system
通过top命令查看节点监控数据:kubectl top node/pod
[root@master01 ~]# kubectl top node
[root@master01 ~]# kubectl top pod -n kube-system

到此为止metrics-server安装成功。

HPA 应用案例

案例:创建HPA,通过HPA对Pod数量进行弹性自动伸缩

# 获取HPA支持的配置属性
kubectl explain hpa.spec
[root@master01 ~]# vim hpa-deploy_nginx.yml
apiVersion: autoscaling/v1 #自动扩缩容版本
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-nginx
  namespace: test
  
spec:
  minReplicas: 1 #最小的pod数量
  maxReplicas: 10 #最大的pod数量
  targetCPUUtilizationPercentage: 1 #cpu使用指标,表示10%(生产环境建议定义在6-8)
  scaleTargetRef: #指定要控制的deploy信息
    apiVersion: apps/v1 #deploy版本
    kind: Deployment #deploy类型
    name: deploy-nginx #deploy名称
    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels:
      app: deploy-nginx #标签
   template: #创建Pod模板
     metadata:
       labels:
         app: deploy-nginx #pod的标签
     spec:
       # 容忍
       tolerations:
       - key: worker01
         effect: NoSchedule
       containers:
       - name: nginx
         image: nginx:1.18.0
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
         resources: #资源限额
           limits: #资源上限
           cpu: 100m #cpu 1核心的10%的资源(生产环境建议600m-800m)
           
创建HPA类型的deploy
[root@master01 ~]# # kubectl create -f hpadeploy_nginx.yml
查看信息
[root@master01 ~]# kubectl get deploy,pod,hpa -n test

HPA 弹性伸缩

另开终端动态查看pod信息
[root@master01 ~]# kubectl get po -n test -w
查看Pod地址
# kubectl get pod -n test -o wide
通过压力测试工具访问Pod地址进行压力测试
[root@master01 ~]# yum -y install httpd-tools
[root@master01 ~]# ab -n 300000 -c 100 http://10.244.30.104/index.html
-n 请求的总数量
-c 并发数量

17、控制器 Statefulset

什么是statefulset?

StatefulSet 是用来管理有状态的应用,例如数据库。
前面我们部署的应用,都是不需要存储数据,不需要记住状态的,可以随意扩充副本,每个副本都是一样的,可替代的。
而像数据库、Redis 这类有状态的,则不能随意扩充副本。
StatefulSet 会固定每个 Pod 的名字

特性

  • 仅当前一个 pod 启动,才会运行后一个(redis-statefulset-0 处于 running 状态,才会运行 redis-statefulset-1)
  • Pod 的名称的形式为<statefulset name>-<ordinal index>
  • Service 的 CLUSTER-IP 是none,Pod 名字也是固定的。
  • Pod 创建和销毁是有序的创建是顺序的销毁是逆序的。(可以使用 kubectl scale 或者kubectl patch 来扩容/缩容测试,或者去修改 yaml 文件 replicas 参数)
  • 删除 pod,pod 会自动重建,重建不会改变Pod 的序号、主机名、SRV 条目和记录名称,IP会改变(每次删除 pod,删除 pod 的 IP 已被占用,新建时 IP 会追加),不要使用 IP 连接

部署 StatefulSet 类型的 redis

  1. 创建 StatefulSet 以及 service
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-statefulset
spec:
  serviceName: redis-service
  replicas: 3
  selector:
    matchLabels:
      app: redis-statefulset
  template:
    metadata:
      labels:
        app: redis-statefulset
    spec:
      containers:
        - name: redis
          image: redis:latest
          # IfNotPresent 仅本地没有镜像时才远程拉,Always 永远都是从远程拉,Never 永远只用本地镜像,本地没有则报错
          imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  selector:
    app: redis-statefulset
  type: ClusterIP
  # HeadLess
  clusterIP: None
  ports:
    - port: 6379
      targetPort: 6379

使用 kubectl apply -f redis-StatefulSet.yaml 创建 statefulset (redis-statefulset-0、redis-statefulset-1、redis-statefulset-2) 以及 service (redis-service )

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

七、Service 四层负载均衡

本章主要学习k8s的流量负载组件:Service与ingress,Service用于4层流量的负载,ingress用于7层流量负载。

Service介绍

在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。

为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。

  • service是实现负载均衡功能,主要实现四层负载,通过ip + 端口 进行转发的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Kube-proxy介绍

Service的本质就是一条代理规则,真正实现代理功能的其实是kube-proxy代理组件,集群的每个节点都运行着一个kube-proxy服务进程,当创建Service的时候,就等于创建了一条代理规则,而这条规则就是告诉kube-proxy 通过那种模式进行流量转发。

kube-proxy代理模式介绍

kube-proxy三种代理模式:UserSpace模式、iptables模式、ipvs模式

Userpace模式介绍

userspace模式下,用户的请求会发向Cluster IP被Iptables规则重定向到kube-proxy监听的端口上。

该模式下,kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,在转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

iptables模式介绍

iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ipvs模式介绍

ipvs(Virtual Server)与iptables类似,都是基于 netfilter 进行流量转发,kube-proxy也不承担四层负载均衡器的角色,只创建ipvs规则,ipvs在转发时支持的负载均衡算法非常的灵活,例如:轮询、加权轮询、基于端口转发、最小负载、最少连接等,ipvs 支持服务器健康检查连接重试等功能。

ipvs 模式的实现原理图示如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

想要使用ipvs转发模式需要安装ipvs内核模块,否则会降级为iptables模式

查看ipvs模块(本实验环境在第二章集群环境部署时已经安装)
[root@master01 ~]# lsmod | grep -e ip_vs -e
nf_conntrack_ipv4
nf_conntrack_ipv4
nf_defrag_ipv4
ip_vs_sh
ip_vs_wrr
ip_vs_rr
ip_vs
nf_conntrack
libcrc32c

开启ipvs,编辑kube-proxy文件
[root@master01 ~]# kubectl edit cm kube-proxy -n kube-system
mode: "ipvs" #修改为ipvs模式
#提示:cm(ConfigMap)在K8s中属于配置资源
删除当前正在使用的kube-proxy的pod(按照标签删除)
[root@master01 ~]# kubectl get pod --show-labels -n kube-system | grep kube-proxy*
[root@master01 ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
查看kube-proxy的pod是否被重建
[root@master ~]# kubectl get po -n kube-system
查看ipvs功能是否开启
[root@master01 ~]# ipvsadm -Ln

Service常用访问方式介绍

  • ClusterIP:默认访问方式,分配一个集群内部可以访问的虚拟IP(该方式只能用于集群内部访问,外部无法访问)
  • NodePort:在每个Node上分配一个端口作为外部访问入口,端口范围为30000-32767(该访问适用于外部访问)
  • LoadBalancer:通过在集群外部的公有云平台上,例如:阿里云、华为云、AWS等做一个负载均衡,通过外部负载均衡将流量转发到集群中。

访问过程:用户----->域名----->云服务提供商提供LB负载均衡设备-----> NodeIP:Port(service IP)----->Pod IP:端口

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Service资源清单文件介绍

kubectl explain svc 查看service资源支持的属性

apiVersion: v1 #版本
kind: Service #资源类型
metadata: #元数据
  name: #资源名称
  namespace: #所属名称空间
spec: #描述
  selector: #标签选择器,用于确定当前service代理哪些pod
    app: #标签
  type: Service  #类型
  clusterIP: clusterIP  #访问方式
  ports: 端口信息
    - protocol: TCP     #端口协议
      port:         #访问Service使用的端口
      targetPort:         # pod中容器的端口
      nodePort: node端口    #(Service需要暴露给外部访问的节点端口,端口范围:30000-32767)
      

Cluster IP 应用案例

案例:通过HPA创建3个Pod并设置标签为app=deploy-nginx(使用前面的hpa-deploy_nginx.yml创建即可)通过Service ClusterIP访问方式进行代理

ClusterIP:默认访问方式,由k8s自动分配的虚拟IP,只能在集群内部访问

[root@master01 ~]# vim hpa-deploy_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test

spec:
  type: ClusterIP #service默认访问方式
  ports:  #定义端口信息
  - port: 80  #访问service使用的端口,可自定义
      targetPort: 80 #pod中容器端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-nginx #标签(需要下方代理的Pod标签一致)

---
apiVersion: autoscaling/v1 #自动扩缩容版本
kind: HorizontalPodAutoscaler #类型
metadata:
  name: hpa-nginx
  namespace: test
spec:
  minReplicas: 3  #最小的pod数量
  maxReplicas: 10 #最大的pod数量
  targetCPUUtilizationPercentage: 6 #cpu使用指标,表示60%
  scaleTargetRef: #指定要控制的Pod控制器(deploy)信息
    apiVersion: apps/v1
    kind: Deployment #deploy控制器类型
    name: deploy-nginx #deploy控制器名称(要在k8s中存在)
  
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 3 #创建pod的副本数量,默认为1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
        
  spec:
    containers:
    - name: nginx
      image: nginx:1.17.0 #指定镜像
      ports: #定义端口
      - containerPort: 80 #端口
        protocol: TCP #端口协议
      resources: #资源限额
        limits: #资源上限
          cpu: 600m  # cpu 1核心的60%的资源
创建Pod
[root@master01 ~]# kubectl create -f hpa-deploy_nginx.yml
查看pod详细信息
[root@master01 ~]# kubectl get pod -n test
[root@master01 ~]# kubectl get pod -n test -o wide

为了更好的验证用户请求被分配到哪个pod中,修改3个Pod中nginx默认首页为具体的Pod IP地址
[root@master01 ~]# kubectl exec -it deployment-6696798b78-6zl8p -n test /bin/bash
[root@master01 ~]# echo "10.244.1.44" > /usr/share/nginx/html/index.html

访问3个pod测试
[root@master01 ~]# curl http://10.244.1.44
10.244.1.44
[root@master01 ~]# curl http://10.244.2.24
10.244.2.24
[root@master01 ~]# curl http://10.244.1.45
10.244.1.45
查看svc信息
[root@master01 ~]# kubectl get svc -n test
[root@master ~]# kubectl describe svc -n test
Name: service
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP: 10.96.96.96
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints:
10.244.1.44:80,10.244.1.45:80,10.244.2.24:80 代理的pod地址
Session Affinity: None
Events: <none>
查看ipvs的映射规则
[root@master01 ~]# ipvsadm -Ln
...
TCP 10.96.96.96:80 rr
-> 10.244.1.44:80 Masq 1 0 0
-> 10.244.1.45:80 Masq 1 0 0
-> 10.244.2.24:80 Masq 1 0 0
#rr为默认轮询策略:当service接收到请求后,会通过轮询算法将请求分配到对应的三个pod中

访问测试
[root@master01 ~]# while :
do
  curl 10.96.96.96
  sleep 5
done
10.244.2.24
10.244.1.45
10.244.1.44
10.244.2.24
10.244.1.45
10.244.1.44

删除Pod
[root@master ~]# kubectl delete -f hpa-deploy_nginx.yml

总结:Cluster IP的访问方式只能用在集群内部主机之间访问,集群外部主机没办法访问。

NodePort 应用案例

在生产环境中,Service是需要暴露给外部访问的,那么就要用到NodePort类型的Service,NodePort的工作原理其实就是在Node节点上暴露一个端口,然后外部主机就可以通过 节点IP + 暴露端口来访问集群中的pod了

案例:将前边案例中的清单文件Cluster IP改为NodePort 类型,实现外部访问。

[root@master01 ~]# vim hpa-deploy_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  type: NodePort service类型
  ports: #定义端口信息
  - port: 80 #访问service使用的内部端口,可自定义
    targetPort: 80 #指定pod中容器端口
    nodePort: 30007 外部访问service的端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-nginx #标签(需要与代理的Pod标签一致)
    
---
apiVersion: autoscaling/v1 #自动扩缩容版本
kind: HorizontalPodAutoscaler #类型
metadata:
  name: hpa-nginx
  namespace: test
  
spec:
  minReplicas: 3 #最小的pod数量
  maxReplicas: 10 #最大的pod数量
  targetCPUUtilizationPercentage: 6 #cpu使用指标,表示60%
  scaleTargetRef: #指定要控制的nginx信息
    apiVersion: apps/v1
    kind: Deployment #deploy类型
    name: deploy-nginx #deploy名称
    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 3
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
  metadata:
    labels:
      app: deploy-nginx #pod的标签
  spec:
   containers:
   - name: nginx
     image: nginx:1.17.0 #指定镜像
     ports: #定义端口
     - containerPort: 80 #端口
       protocol: TCP #端口协议
     resources: #资源限额
       limits: #资源上限
         cpu: 600m #cpu 1核心的60%的资源
创建Pod
[root@master01 ~]# kubectl create -f hpa-deploy_nginx.yml
查看Pod信息
[root@master01 ~]# kubectl get pod -n test
查看Service信息
[root@master01 ~]# kubectl get svc -n test
NAME       TYPE      CLUSTER-IP    EXTERNAL-IP  PORT(S)   AGE
svc-nginx NodePort 10.110.174.205   <none>    80:32388/TCP  13s
提示:
80 #Service端口
32388 #Service绑定的Node节点端口,这个端口是提供外部访问的

外部主机访问测试(通过宿主机主机IP加Node端口,访问集群中任何一台节点IP都可以)
http://192.168.0.13:32388

删除Pod
[root@master01 ~]# kubectl delete -f hpa-deploy_nginx.yml

八、Ingress 七层负载

1、Ingress 控制器介绍

Ingress 是 Kubernetes 集群中的一种资源对象,用于管理对集群内部的服务的访问。它充当着入口的角色,通过定义规则来将外部的请求路由到集群内部的服务。

Ingress控制器种类有很多(以nginx为例)的工作原理:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • 用户编写Ingress规则,说明哪个域名对应集群中的Service

  • Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置进行流量转发

2、Nginx Ingress 环境搭建

  • ingress-nginx资源清单文件下载地址:https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml

提示:由于网络原因可能无法下载,直接使用我给大家下载好的文件即可,文件名:deploy.yml

创建ingress-nginx
[root@master01 ingress-nginx]# kubectl create -f deploy.yaml
查看ns(会有一个ingress-nginx的命名空间)
[root@master01 ingress-nginx]# kubectl get ns
...
ingress-nginx Active 2m27s
查看详细信息时会出现如下报错:
# kubectl describe pod -n ingress-nginx
MountVolume.SetUp failed for volume "webhook-cert" :secret "ingress-nginx-admission-token-bnrl4" not found
#这个报错原因是当前运行的ingress-nginx-admission-token名称与deploys.yml文件中的名称不一致,需要对文件进行修改

解决方法:查看ingress的secret

[root@master01 ingress-nginx]# kubectl get secret -A | grep ingress
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
复制这个名称到deploy.yml文件替换默认的名称
[root@master01 ingress-nginx]# vim deploy.yaml
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
修改后再次更新资源文件
[root@master01 ingress-nginx]# kubectl apply -f deploy.yaml
查看ingress-nginx空间的pod(有两个Pod用于执行一次性任务,状态为
Completed(完成),这种Pod执行后即退出。)
[root@master01 ingress-nginx]# kubectl get po -n ingressnginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-cctfh 0/1 Completed 0 28m
ingress-nginx-admission-patch-rhzrk  0/1 Completed 1 28m
ingress-nginx-controller-9d98d6467-2wtnj 1/1 Running 0 23m
查看service
[root@master01 ingress-nginx]# kubectl get svc -n ingress-nginx
NAME         TYPE   CLUSTER-IP   EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort
10.99.98.180 <none>  80:31770/TCP,443:31082/TCP17m 
ingress-nginx-controller-admission ClusterIP
10.97.42.155 <none> 443/TCP         17m
#提示:到此为止ingress-nginx的控制器已经安装完毕

3、Nginx Ingress HTTP 应用案例

案例:通过Deployment部署tomcat与nginx的pod,并通过Nginx Ingress进行HTTP访问

[root@master01 ~]# vim ingress-http.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-nginx
    template:
      metadata:
        labels:
          app: deploy-nginx
      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0
          ports:
          - containerPort: 80
          
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
  
spec:
  selector:
    app: deploy-nginx
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 80
    targetPort: 80
    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-tomcat
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-tomcat
  template:
    metadata:
      labels:
        app: deploy-tomcat
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080
        
---
apiVersion: v1
kind: Service
metadata:
  name: svc-tomcat
  namespace: test
spec:
  selector:
    app: deploy-tomcat
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 8080
    targetPort: 8080
    
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-http #自定义ingress名称
  namespace: test
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true" # 指定spec下方的rules的path可以使用正则表达式,如果我们没有使用正则表达式,此项则可不使用
    kubernetes.io/ingress.class: nginx #指定控制器的类别为nginx
    
spec:
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-nginx #对应上面创建的service名称
            port:
              number: 80 #service端口
              
  - host: www.tomcat.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-tomcat #对应上面创建的service名称
            port:
              number: 8080 #service端口
#### 创建ingress报错
[root@master01 data]# kubectl apply -f ingress-nginx.yml
Error from server (InternalError): error when creating"ingress-nginx.yml": Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io":failed to call webhook: Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": remote error: tls: internal error

查看ingress-nginx-admission
# kubectl get validatingwebhookconfigurations
删除ingress-nginx-admission
# kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
重新创建ingress
# kubectl apply -f ingress-nginx.yml
查看信息
[root@master01 ~]# kubectl get all -n test
查看ingress信息
[root@master01 ~]# kubectl get ing -n test
查看详细信息
[root@master01 ~]# kubectl describe ing -n test

测试Ingress HTTP代理

浏览器访问由于域名无法正常解析,需要在windows内进行解析:C:\Windows\System32\drivers\etc

192.168.0.13 www.nginx.com www.tomcat.com

访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问

查看ingress-nginx暴露的端口
[root@master01 ~]# kubectl get svc -n ingress-nginx
NAME           TYPE     CLUSTER-IP EXTERNAL-IP PORT(S)          AGE
ingress-nginx NodePort 10.97.31.167 <none>     80:30256/TCP,443:31232/TCP 21

访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口

http://www.nginx.com:30256
http://www.tomcat.com:31232

删除ingress http

[root@master01 ~]# kubectl delete -f ingress-http.yml

4、Nginx Ingress HTTPS 应用案例

案例:通过Deployment部署tomcat与nginx的pod,并通过Nginx Ingress进行HTTPS访问

生成证书

[root@master01 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=TJ/O=nginx/CN=thinkmo.com"

创建密钥

[root@master01 ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt

创建ingress https

[root@master ~]# vim ingress-https.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
  
spec:
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
        
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  selector:
    app: deploy-nginx
  clusterIP: None #不分配集群IP(用不着)
  type: ClusterIP #service类型
  ports:
  - port: 80
    targetPort: 80
    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-tomcat
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-tomcat
  template:
    metadata:
      labels:
        app: deploy-tomcat
    spec:
      containers:
        - name: tomcat
          image: tomcat:8.5-jre10-slim
          ports:
          - containerPort: 8080
          
---
apiVersion: v1
kind: Service
metadata:
  name: svc-tomcat
  namespace: test
spec:
  selector:
    app: deploy-tomcat
  clusterIP: None #不分配集群IP(用不着)
  type: ClusterIP #service类型
  ports:
  - port: 8080
    targetPort: 8080
    
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-https #自定义ingress名称
  namespace: test
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
    kubernetes.io/ingress.class: nginx #注释名称需为nginx(不可省略)
spec:
  tls:
  - hosts:
    - www.nginx.com #指定域名使用的证书
    - www.tomcat.com #指定域名使用的证书
    secretName: tls-secret #指定secret名称(与前边创建的保持一致)
    
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-nginx #对应上面创建的service名称
            port:
              number: 80 #service端口
  - host: www.tomcat.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-tomcat #对应上面创建的service名称
            port:
              number: 8080 #service端口
创建Pod
[root@master01 ~]# kubectl create -f ingress-https.yml 
ingress.extensions/ingress-https created
查看ingress信息
[root@master01 ~]# kubectl get ing ingress-https -n test
NAME    CLASS    HOSTS    ADDRESS   PORTS   AGE
ingress-https <none> www.nginx.com,www.tomcat.com 192.168.0.13 80, 443 5m37s
查看详细信息
[root@master ~]# kubectl describe ing ingress-https -n dev
...
tls-secret terminates www.nginx.com,www.tomcat.com #密钥
...

查看ingress-nginx端口

[root@master01 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.97.31.167 <none> 80:30256/TCP,443:31232/TCP 22h

九、ConfigMap、Secret配置与密钥管理

1、ConfigMap介绍

我们在部署应用的时候, 许多应用程序会从配置文、命令行参数或环境变量中读取所需的配置信息,这些配置信息需要与docker image解耦

如果这些应用数量较多且分散在集群的不同节点上,而我们又需要对这些节点的服务配置进行批量修改,如果每个服务都单独修改的话,那么更新配置就很麻烦, 所以k8s中引入了Configmap资源对象, 提供了向容器中注入配置信息的机制,主要作用就是为了让服务和配置文件解耦,以便实现配置的统一管理。

Configmap是k8s中的资源,以键值对的形式保存一些非机密性数据, 相当于配置文件。

使用 ConfigMap 的限制条件:

  1. ConfigMap 需要在 Pod 启动前创建出来;

  2. 并且只有当 ConfigMap 和 Pod 处于同一命名空间时,才可以被 Pod引用;

  3. 当 Pod 挂载 ConfigMap 绑定的目录时,目录下的目录并不会挂载到Pod 内,只有目录下的文件会被挂载。

  4. ConfigMap在设计上不是用来保存大量数据的,在ConfigMap中保存的数据不可超过1 MiB,如果你需要保存超出此限制的数据,可以考虑挂载存储卷

2、ConfigMap创建与使用

通过文件创建confifigmap, 格式: --from-file=文件名

一般比较常见的使用方式便是使用文件创建,因为在有些时候可能需要对配置进行批量的更新。这样会更加的方便。

# cat /opt/nginx.conf
server {
	listen 8000;
	server_name _;
	location / {
		root /usr/share/nginx/html;
		index index.html index.htm;
	}
}
# kubectl create cm cm-ngx-config --from-file=/opt/nginx.conf -n test
# kubectl get cm -n test
# kubectl describe cm cm-ngx-config -n test

创建nginx的Pod,并使用Volume将ConfifigMap挂载到nginx容器中

# cat cm-nginx-config.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-nginx
  template:
    metadata:
      labels:
        app: web-nginx
    spec:
      volumes:
      - name: nginx-config # 卷的名称(自定义)
        configMap: # 卷类型是configMap
          name: cm-ngx-config # configmap的名称
      containers:
      - name: web-nginx
        image: nginx:1.18-alpine
        ports:
        - containerPort: 80
        volumeMounts: # 定义在容器中挂载的信息
        - name: nginx-config # 挂载的名称(上边定义的卷的名称)
          mountPath: /etc/nginx/conf.d # 挂载到容器的路径
# 创建pod
kubectl create -f cm-nginx-configmap.yml
# kubectl get pod -n test
NAME READY STATUS RESTARTS AGE
web-nginx-5684fbc5dc-js6jg 1/1 Running 0 23s

提示:将目录A挂载到目录B,则目录B原有的文件都会被目录A下的文件覆盖。如果你想挂载的目录下有其他文件,默认会覆盖目录下其他文件,可以通过subPath属性挂载

...
spec:
      containers:
      - name: web-nginx
        image: nginx:1.18-alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf # key的名称(文件名)
      volumes:
      - name: nginx-config
         configMap:
           name: cm-ngx-config # configmap的名称

subPath的使用方法一共有两种:
1. 同一个pod中多容器挂载同一个卷时提供隔离
2. 将configMap和secret作为文件挂载到容器中而不覆盖挂载目录下的文件(默认会覆盖)

提示:以subPath方式挂载时,configmap更新,容器不会更新,解决方式,可以把文件挂载到一个空目录,然后使用ln链接过去

3、ConfigMap热更新

通过Volume挂载到容器内部时,当该configmap的值发生变化时,容器内部具备自动更新的能力,但是通过环境变量设置到容器内部该值不具备自动更新的能力。

更新cm-ngx-config的cm内容为80

apiVersion: v1
data:
  nginx.conf: |
    server {
        listen 80; # 改为80
        server_name _;
        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
    }
}
kind: ConfigMap
metadata:
  creationTimestamp: "2022-11-03T06:41:40Z"
  name: cm-ngx-config
  namespace: test
  resourceVersion: "20386"
  uid: 6024477f-3d12-4780-8b52-39929be45bbc

访问是80端口发现失败,但从pod中查询nginx的配置文件,发现已经更改为80,说明configmap热更新已生效,这时就需要手动触发滚动更新才能再次加载nginx的配置文件。

# kubectl patch deployment web-nginx -n test --patch'{"spec": {"template": {"metadata": {"annotations":{"version/config": "20221103" }}}}}'

这个命令是在 .spec.template.metadata.annotations 中添加version/config标签,每次通过修改 version/config 来触发滚动更新。

...
template:
  metadata:
    annotations:
      version/config: "20221103"
...

4、Secret介绍

Secret与ConfifigMap类似,主要的区别是ConfigMap存储的是明文,而Secret存储的是密文。

可以用于存储和管理一些敏感数据,比如密码,token,密钥,证书等敏感信息。

它把 Pod 想要访问的加密数据存放到 Etcd 中,然后用户就可以通过在Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret里保存的信息了。

Secret有4种类型:

  • Opaque: base64编码格式的Secret,用来存储密码、密钥,类型标识符为generic

  • Service Account: 用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod

    /var/run/secrets/kubernetes.io/serviceaccount目录中

  • kubernetes.io/dockerconfifigjson: 用来存储私有docker registry的认证信息,类型标识为docker-registry。

  • kubernetes.io/tls: 用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。

# kubectl create secret -h
Create a secret using specified subcommand.
Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic Create a secret from a local file,directory or literal value tls Create a TLS secret

5、Secret应用案例

使用Opaque类型来存储mysql的root密码。

Opaque类型需要将明文密码进行base64编码

# echo -n 123456 | base64
MTIzNDU2
明文密码为123456,得到的编码为MTIzNDU2

提示: echo -n 不换行输出,如果不使用-n,就会把换行符也作为了字符当做密码使用,所以一直报错进不去mysql

编写创建secret的YAML文件

# cat secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
  namespace: test
data:
  password: MTIzNDU2

创建secret

kubectl apply -f secret-mysql.yml
kubectl get secret -test |grep secret-mysql

6、Secret使用方式

创建MySQL的Pod,并通过环境变量的方式传递给pod使用。

# cat pod-mysql-secret.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-mysql
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-mysql
  template:
    metadata:
      labels:
        app: deploy-mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 80
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: secret-mysql # 对应创建的secret名字
              key: password

验证传入pod的变量效果

root@pod-mysql-secret1:/# env | grep MYSQL_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=123
root@pod-mysql-secret1:/# mysql -p123456

7、Secret热更新

# echo -n 123456789 |base64
MTIzNDU2Nzg5

# kubectl edit secret secret-mysql -n test
apiVersion: v1
data:
  password: MTIzNDU2Nzg5 # 修改密码
kind: Secret
metadata:

补充:通过环境变量的方式使用的secret或者confifigmap都无法热更新。

这时就需要手动触发滚动更新

# kubectl patch deployment deploy-mysql -n test --patch '{"spec": {"template": {"metadata": {"annotations":{"version/config": "20221103" }}}}}'

十、容器镜像仓库Harbor

Docker官方提供了Registry镜像仓库,但是Registry的功能相对简陋。Harbor是VMware公司提供的一款镜像仓库,提供了权限控制、分布式发布、强大的安全扫描与审查机制等功能

Harbor 私有仓库,它以 Registry 为基础,提供了对用户友好的管理界面,可以帮助我们快速搭建一个企业级的 Docker Registry 服务。

Harbor 的每个组件都是以 Docker 容器的形式构建的,使用 DockerCompose 进行部署。

Harbor优势

  • 基于角色控制:有管理员与普通用户,可赋权普通⽤户,比如只能上传和下载,可根据项⽬来进⾏操作和管理。
  • 基于镜像的复制策略:也与权限相关,比如有只⼀些⽤户与组才能对此项⽬进⾏相对应的操作。
  • ⽀持LDAP/AD域控制:比如南京去下载北京harbor私有仓库的镜像,两端打上局域网的地址,连接在一块,数据信息的传输通过⼀条隧道,会通过两层加密,第⼀层为隧道加密,第⼆层为数据加密,安全可靠。
  • 图像删除和垃圾收集:即回收站机制。
  • 图形UI:具有统计功能,比如访问量与镜像下载热度。

1、docker安装

1.1、安装docker

使用阿里云开源软件镜像站。
# wget https://mirrors.aliyun.com/dockerce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/dockerce.repo
安装docker-ce
# yum -y install docker-ce && systemctl enable --nowdocker

1.2、docker compose

harbor通过docker-compose进行管理,需要提前下载docker-compose二进制文件
# wget https://github.com/docker/compose/releases/download/1.25.0/docker-compose-Linux-x86_64
移动二进制文件到/usr/bin目录,并更名为docker-compose
# mv docker-compose-Linux-x86_64 /usr/bin/docker-compose
为二进制文件添加可执行权限
# chmod +x /usr/bin/docker-compose
安装完成后,查看docker-compse版本
# docker-compose version

**1.3、安装 **harbor仓库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
下载harbor离线安装包
# wget https://github.com/goharbor/harbor/releases/download/v2.5.1/harbor-offline-installer-v2.5.1.tgz
解压harbor
# tar xf harbor-offline-installer-v2.5.1.tgz -C /

创建配置文件
# cd harbor/
# mv harbor.yml.tmpl harbor.yml

导入Harbor所需的镜像文件
#docker load -i harbor.v2.5.1.tar.gz
修改配置文件中的如下内容
# vim harbor.yml
#上述内容省略...
hostname: 192.168.0.17 指定Harbor主机地址
http: #访问方式为http(不用修改)
  port: 80 #默认端口(不用修改)
  
https: 注释https访问方式(需要证书才可以使用)
  port: 443 注释端口
  certificate: /root/harbor/6864844_kubemsb.com.pem #注释证书文件
  private_key: /root/harbor/6864844_kubemsb.com.key #注释证书密钥文件
harbor_admin_password: 12345 访问密码
执行预备脚本(下载harbor所需的镜像文件)
# ./prepare 

执行安装脚本
# ./install.sh
...

✔ ----Harbor has been installed and started
successfully.----

验证运行情况
# docker ps
默认的用户名:admin,密码是前边配置文件中设置的密码:12345
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示:以下操作需要在集群所有节点指定harbor仓库地址

harbor主机修改后直接将修改后的文件拷贝到所有节点即可
[root@harbor harbor]# vim /etc/docker/daemon.json
{
	"insecure-registries": ["http://192.168.0.25"]
}
停止harbor后重启docker
[root@harbor harbor]# docker-compose down
[root@harbor harbor]# systemctl daemon-reload && systemctl restart docker

启动harbor
[root@harbor harbor]# docker-compose up -d
k8s集群所有节点也都需要指定Harbor仓库的地址
[root@harbor harbor]# for i in master02 master03 worker01
do
 scp /etc/docker/daemon.json $i:/etc/docker/
done

所有节点重启docker
[root@harbor harbor]# for i in master02 master03 worker01
do
  ssh $i systemctl daemon-reload && systemctl restart docker
done

1.4、镜像上传到Harbor仓库

通过命令行登录到harbor仓库才能上传镜像
[root@harbor harbor]# docker login 192.168.0.25
Username: admin --Harbor的web界面的用户名称
Password:12345 --密码

修改镜像标签
[root@harbor harbor]# docker tag choujiang:v1 192.168.0.25/image/choujiang:v1

上传镜像
[root@harbor harbor]# docker push choujiang:v1/image/choujiang:v1

2、K8s集群使用Harbor仓库

2.1、通过密钥的方式创建

创建一个给 Docker registry 使用的 secret

k8s中的secrets用于存储和管理一些敏感数据,比如密码,token,密钥等敏感信息。它把 Pod 想要访问的加密数据存放到 Etcd 中。然后用户就可以通过在 Pod 中表明具体的方式访问到这些 Secret 里保存的信息了。

[root@master01 ~]# kubectl create secret docker-registry docker-harbor --docker-server=192.168.0.25 --docker-username=admin --docker-password=12345 --namespace=test -o yaml > docker-harbor.yaml

说明:
kubectl create secret #创建命令
docker-registry #资源类型
docker-harbor #名称(自定义)
  --docker-server #指定harbor仓库的IP
  --docker-username #指定harbor仓库的登录用户名
  --docker-password #指定harbor仓库的登录密码
  --namespace=test #指定命名空间

提示:这个secret只针对于test命名空间生效,其他命名空间的Pod无法使用该secret拉取镜像,如果其他命名空间需要使用secret,需在指定的空间再次创建。

# 验证
[root@master01 ~]# kubectl get secret -n test | grep docker-harbor
[root@master01 ~]# kubectl describe secret docker-harbor -n test

2.2、创建pod并使用secret

[root@master01 ~]# vim nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test

spec:
  type: NodePort #service类型
  ports: #定义端口信息
  - port: 80 #访问service使用的端口,可自定义
    targetPort: 80 #指定pod中容器端口
    nodePort: 30007 #自定义service端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-nginx #标签(需要与代理的Pod标签一致)
    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      imagePullSecrets: #定义镜像下载使用的secrets
      - name: docker-harbor #secret名称,与上边创建名称保持一致
        containers:
        - name: nginx
          image: 192.168.0.25/image/choujiang_ngx:v1 #指定镜像
          
创建Pod
[root@master01 ~]# kubectl create -f nginx.yml

2.3、验证pod镜像下载地址

[root@master01 ~]# kubectl describe pod -n test

Harbor使用注意事项

当docker重启后,harbor服务需要先关闭在进行重启才可以正常使用

关闭harbor方式(进入到harbor路径)
[root@harbor harbor]# docker-compose down

启动harbor
[root@harbor harbor]# docker-compose up -d

查看harbor容器,总共有九个容器
[root@harbor harbor]# docker ps
harbor-jobservice
nginx
harbor-core
registryctl
registry
harbor-portal
harbor-db
redis
harbor-log

十一、基于K8S的DevOps

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1、GitLab 环境准备

安装gitlab

 yum -y install gitlab-ce-14.1.0-ce.0.el7.x86_64.rpm

配置GitLab URL

# vim /etc/gitlab/gitlab.rb
...
external_url 'http://192.168.0.15'

修改完主配置文件后,使用gitlab-ctl reconfifigure重新配置gitlab使配置生效

# gitlab-ctl reconfigure

提示:gitlab-ctl reconfifigure一般修改完主配置文件/etc/gitlab/gitlab.rb,需要执行此命令

查看GitLab服务状态

# gitlab-ctl status
root初始密码所在文件:/etc/gitlab/initial_root_password
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
通过个人资料中心修改root密码
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
密码不验证复杂度,长度需满足8位
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
修改页面语言
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.1、关闭注册功能

由于我们Gitlab系统是私有仓库,一般用户都是由管理员创建和分派的,所以我们需要关闭注册。

点击左上角 菜单(Menu)→管理(Admin)→通用,找到注册限制取消掉注册功能。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
将勾选取消,点击 保存更改(Save changes

1.2、新建群组

群组就是把相关的项目和用户放在一起,进行统一的权限管理。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在可见性级别处我们选择私有,这样只有经过授权的用户才可以看到该组内的项目,其他用户无法查看。

1.3、创建仓库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.4、安装Docker

通过docker构建镜像,将构建好的镜像推送到GitLab仓库。

# wget https://mirrors.aliyun.com/dockerce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

# yum -y install docker-ce && systemctl enable docker --now

下载nginx镜像用于构建dockerfile
# docker pull nginx:1.18.0

1.5、安装Git推送项目

# yum -y install git

将代码推送到choujiang项目中

初始化目录为Git版本库
# git init
# git config --global user.email "yesir@163.com"
# git config --global user.name "yesir"

解压项目
# unzip dzp.zip
# rm -rf dzp.zip
# mv luckdraw-master/* .

构建dockerfile
# vim dockerfile
FROM nginx:1.18.0
ADD . /usr/share/nginx/html
解释:将当前项目文件添加到nginx网页目录

构建镜像
# docker build -t choujiang:v1 .

创建容器
# docker run -id --name choujiang -p 88:80 choujiang:v1

访问测试:http://192.168.0.15:88/
上传项目到仓库
# git add .
# git commit -m 'add choujiang'

添加远程仓库
# git remote add origin git@192.168.0.110:test/choujiang.git
推送项目到远程仓库
# git push -u origin master

2、Jenkins环境部署

清华大学下载Jenkins稳定版地址:https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/

Jenkins需要依赖Java环境,需要提前安装jdk环境(fontconfifig软件提供Jenkins web界面字体)

# yum install fontconfig java-11-openjdk -y

安装Jenkins

# yum localinstall jenkins-2.332.3-1.1.noarch.rpm

2.1、相关参数

程序名:jenkins
默认端口:8080(可修改)
/etc/sysconfig/jenkins    #配置文件,主要配置Jenkins的工作目录、启动用户、启动端口
/var/lib/jenkins          #默认的Jenkins家目录(存放项目及插件)
/var/log/jenkins          #日志文件目录

启动Jenkins
# systemctl start jenkins
# systemctl enable jenkins
查看Jenkins端口信息
# netstat -ntlp
tcp6 0 0 :::8080 :::* LISTEN 7703/java

查看本版本信息
jenkins --version

提示:如果使用较新版本在启动服务时,服务无法启动,请使用较低版

本,因为有可能出现Jenkins和Java的版本不兼容的情况。

浏览器访问jenkins:192.168.0.16:8080
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
安装插件:安装推荐的插件
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、Jenkins与GitLab协同

接下来我们就可以使用Jenkins从Gitlab拉取代码到本机并实现代码的自动发布。

具体流程:

  1. 配置Jenkins与GitLab协同
  2. 拉取项目代码到Jenkins本地
  3. 构建项目发布
安装Git用于拉取GitLab代码
[root@jenkins ~]# yum -y install git

3.1、创建任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示:输入名称之后我们还要点击下面的模板选择其一,否则也无法创建项目,紧接着下面是一些复选框。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解释:本次构建的大致含义是Jenkins将GitLab上的choujiang项目拉取到了Jenkins主机本地:/var/lib/jenkins/workspace/choujiang

查看项目
[root@jenkins ~]# ls /var/lib/jenkins/workspace/choujiang
common css dockerfile image index.html js README.md

3.2、安装Docker构建镜像

# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
# yum -y install docker-ce && systemctl enable docker --now

docker build -t choujiang:v$BUILD_ID .

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示:Jenkins中构建(Build)Docker镜像时出现:dial unix /var/run/docker.sock: permission denied

把这个目录的权限打开
# chmod -R 777 /var/run/docker.sock

构建成功后检查镜像
# docker images

添加harbor仓库地址
# vim /etc/docker/daemon.json
{
	"insecure-registries": ["http://192.168.0.25"]
}
重启服务
# systemctl restart docker

4、Jenkins集成Harbor仓库

回到Jenkins任务,在构建中增加如下命令将镜像并推送到仓库:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
docker build -t choujiang:v$BUILD_ID .
docker login -u admin -p 12345 192.168.0.16
docker tag choujiang:v$BUILD_ID 192.168.0.16/image/choujiang:v$BUILD_ID
docker push 192.168.0.16/image/choujiang:v$BUILD_ID
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.1、创建pod并使用镜像

[root@master01 ~]# vim ingress-http.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      imagePullSecrets: #定义镜像下载使用的secrets
      - name: docker-harbor #secret名称,与上边创建名称保持一致
        containers:
        - name: nginx
          image: 192.168.0.16/image/choujiang:v1 #指定拉取的镜像
        ports:
        - containerPort: 80
        
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  selector:
    app: deploy-nginx
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 80
    targetPort: 80
    
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-http #自定义ingress名称
  namespace: test
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true" #指定spec下方的rules的path可以使用正则表达式
    kubernetes.io/ingress.class: nginx #指定控制器的类别为nginx
    
spec:
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-nginx #对应上面创建的service名称
            port:
              number: 80 #service端口创建Pod
              
[root@master01 ~]# kubectl create -f ingress-http.yml
查看Pod信息
[root@master01 ~]# kubectl get pod -n test
验证pod 镜像下载地址
[root@master01 ~]# kubectl describe pod -n test

访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问

查看ingress-nginx暴露的端口
[root@master01 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.97.31.167 <none> 80:30256/TCP,443:31232/TCP 21

访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口

http://www.nginx.com:30509/

十二、认证及Service、Account、鉴权RBAC

k8s作为一个分布式集群的管理工具,保证集群的安全性是非常重要的任务,所谓的安全性其实就是保证对k8s的各种客户端进行认证和鉴权操作。

k8s 集群的所有的操作基本上都是通过 apiserver 这个组件进行的,k8s对于访问 API 来说提供了三个步骤的安全措施:认证鉴权准入控制

k8s 的认证机制非常多,要想一个个搞清楚也绝非易事,我们只需要掌握几个比较重要且使用广泛的认证机制即可。

1、k8s用户分类

  • 普通用户(k8s用户):可以理解为人通过 kubectl 以及一些客户端工具访问 apiserver 时所需要认证的用户,此类用户嵌入在客户端的证书中。

X509 client certs

X509是一种数字证书的格式标准,现在 HTTPS 依赖的 SSL 证书使用的就是使用的 X509 格式。X509 客户端证书认证方式是 k8s 所有认证中使用最多的一种,相对来说也是最安全的一种,kubernetes的一些部署工具 kubeadm、minkube 等都是基于证书的认证方式。

  • ServiceAccount(服务账户): 指在 kubernetes 集群中的 pod 要访问 apiserver 时所使用的,也就是 serviceaccounts。

2、普通用户

案例:创建一个只能管理test空间下的Pods资源普通用户

普通用户并不是通过k8s来创建和维护,是通过创建证书和切换上下文环境的方式来创建和切换用户。

创建证书私钥文件
# openssl genrsa -out devuser.key 2048

用此私钥文件创建一个csr(证书签名请求)文件
# openssl req -new -key devuser.key -subj "/CN=devuser" -out devuser.csr

拿着证书签名请求文件向apiserver的证书去签署生成证书,签名申请的用户名是devuser
# openssl x509 -req -in devuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out devuser.crt -days 365

生成账号devuser
# kubectl config set-credentials devuser --clientcertificate=./devuser.crt --client-key=./devuser.key --embed-certs=true

查看集群用户信息
kubectl config get-users
NAME
devuser
kubernetes-admin

设置账号上下文并指定名称空间, 信息默认会保存在 $HOME/.kube/config
# kubectl config set-context devuser@kubernetes --cluster=kubernetes --user=devuser --namespace=test

查看上下文信息
# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
devuser@kubernetes kubernetes devuser test
* kubernetes-admin@kubernetes kubernetes kubernetes-admin
提示:*表示当前所处的上下文环境用户

切换到账户devuser(通过上下文名称切换)
# kubectl config use-context devuser@kubernetes
Switched to context "devuser@kubernetes".

查看上下文信息
# kubectl config get-contexts
CURRENT NAME CLUSTER
AUTHINFO NAMESPACE
* devuser@kubernetes kubernetes devuser
test
kubernetes-admin@kubernetes kubernetes
kubernetes-admin
提示:*表示当前所处的上下文环境用户

使用devuser用户查看名称空间下的pod资源
# kubectl get po -n test
Error from server (Forbidden): pods is forbidden: User "devuser" cannot list resource "pods" in API group "" in the namespace "test"
#提示:禁止devuser用户列出test下API组中的pods资源
#解决方法:如果希望devuser用户对test下具备相应的权限,需要通过管理员身份进行授权

切换身份为管理员
# kubectl config use-context kubernetes-admin@kubernetes
# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
devuser@kubernetes kubernetes devuser test
* kubernetes-admin@kubernetes kubernetes kubernetes-admin

3、Service Account

serviceaccounts 是面向 namespace 的,每个 namespace 创建的时候,kubernetes 会自动在这个 namespace 下面创建一个默认(default)的 serviceaccounts;并且这个 serviceaccounts 只能访问该 namespace 的资源。

# cat sa-admin-test.yml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin
  namespace: test
# kubectl get sa -n test
admin 0 5s

3.1、创建Pod并使用Service Account

cat nginx.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-nginx
  template:
    metadata:
      labels:
        app: web-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18-alpine
        ports:
        - containerPort: 80
      serviceAccountName: admin # 指定Pod使用的sa(注意层级关系)
# kubectl apply -f nginx.yml

3.2、默认权限

创建 pod 的时候,如果没有指定 Service Account, 则会使用同一个命名空间下面的 默认的名为 default 的服务账号,默认的服务账号有哪些权限,取决于不同的 k8s 集群。

查看serviceaccount权限格式:
kubectl auth can-i <list|create|delete> pod --as=system:serviceaccount:<namespace>:<serviceaccount> -n <namespace>
# kubectl auth can-i list pod --
as=system:serviceaccount:test:default -n test
no
# kubectl auth can-i list pod --
as=system:serviceaccount:test:admin -n test
no
# kubectl auth can-i create pod --
as=system:serviceaccount:test:default -n test
no
# kubectl auth can-i create pod --
as=system:serviceaccount:test:admin -n test
no
# kubectl auth can-i delete pod --
as=system:serviceaccount:test:default -n test
no
# kubectl auth can-i delete pod --
as=system:serviceaccount:test:admin -n test
no

4、RBAC

ApiServer目前支持以下几种鉴权策略:

  • AlwaysDeny:表示拒绝所有请求,一般用于测试
  • AlwaysAllow:允许接收所有请求,相当于集群不需要授权流程
  • ABAC:基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
  • Webhook:通过调用外部REST服务对用户进行授权
  • Node:是一种专用模式,用于对k8s发出的请求进行访问控制

RBAC介绍

RBAC(Role-Based Access Control)基于角色访问控制,主要用于描述给哪些对象授予了哪些权限,k8s在1.5版本的时候引入了RBAC的权限控制机制,1.6+版本都默认开启了RBAC。

查看方式
# grep -C3 'authorization-mode'
/etc/kubernetes/manifests/kube-apiserver.yaml
	- --audit-log-maxsize=100
	- --audit-log-path=/var/log/kubernetes/audit.log
	- --audit-policy-file=/etc/kubernetes/audit-policy.yml
	- --authorization-mode=Node,RBAC
	- --client-ca-file=/etc/kubernetes/pki/ca.crt
	- --enable-admission-plugins=NodeRestriction
	- --enable-aggregator-routing=true

RBAC中会涉及到下面几个概念:

  • 对象:User、Groups、ServiceAccount(账号)
  • 角色:Role、ClustserRole 代表着一组权限
  • 绑定:RoleBinding、ClusterRoleBinding 用于将角色(权限)跟账号绑定在一起(权限绑定)

绑定关系:

  • Role可以通过RoleBinding与User、Groups进行绑定(不支持与ServiceAccount进行绑定)
  • ClustserRole可以通过RoleBinding和ClusterRoleBinding与User、Groups、ServiceAccount进行绑定

5、Role

一个角色就是一组权限的集合,Role只能对命名空间内的资源进行相应的操作,需要指定namesapce

cat devuser-role.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: test #须指定名称空间
  name: devuser-role #角色名称
  
rules:
- apiGroups: [""] #支持的API组列表,""空字符串,表示核心API群
  resources: ["pods","deployments"] #支持的资源列表
  verbs: ["get", "list", "watch", "create", "update","patch", "delete"] #允许对资源执行的操作

需要详细说明的是rules中的参数

  • apiGroups:支持的API组列表

在使用k8s进行服务的部署过程中我们会使用到Deployment、Service、Pod等资源,在 yaml 文件中我们需要指定对应的 API 版本,我们可以通过访问相应的接口来管理相应的资源信息,在 k8s中为了提高 API 的可扩展性,采用了 API Groups 进行标识这些接口

  • resources:支持的资源对象列表

“services”,“endpoints”,“pods”,“secrets”,“configmaps”,“crontabs”,“deployments”,“jobs”,“nodes”,“rolebindings”,“clusterroles”,“daemonsets”,“replicasets”,“statefulsets”,“horizontalpodautoscalers”,“replicationcontrollers”,“cronjobs”

  • verbs:对资源对象的操作方法列表

“get”,“list”,“watch”,“create”,“update”,“patch”,“delete”,“exec”

创建Role

# kubectl apply -f devuser-role.yml
# kubectl get role -n test
NAME CREATED AT
devuser-role 2022-11-10T08:57:25Z

6、RoleBinding

角色绑定用来把一个角色绑定到一个目标上,绑定目标可以是User、Group或者ServiceAccount

可以把同一个名称空间下的角色与对象之间进行相互的绑定(空间级别的权限绑定)

cat devuser-rolebinding.yml

kind: RoleBinding #角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: devuser-rolebinding #名称自定义
  namespace: test #须指定名称空间
  
subjects: #定义目标对象
  - kind: User #对象类型(User、Groups)
    name: devuser #对象名称(提前创建好)
    apiGroup: rbac.authorization.k8s.io
    
roleRef: #指向的角色
  kind: Role #角色类型(Role、ClustserRole)
  name: devuser-role #角色名称(提前创建好)
  apiGroup: rbac.authorization.k8s.io
  
提示:role不支持与ServiceAccount绑定,只有ClusterRole才可以ServiceAccount绑定

创建RoleBinding

# kubectl create -f devuser-rolebinding.yml
# kubectl get rolebinding -n test
NAME ROLE AGE
devuser-rolebinding Role/devuser-role 12m

切换devuser用户验证权限

# kubectl config get-contexts
# kubectl config use-context devuser@kubernetes
# kubectl get pod -n test
NAME READY STATUS RESTARTS AGE
web-nginx-6cfcdf646-vqhrq 1/1 Running 1 (3h35mago) 2d

提示:该用户对pods只具备"get","watch","list权限",如果想操作pods以外的资源是不可以的

# kubectl get deployment -n test
Error from server (Forbidden): deployments.apps is forbidden: User "devauser" cannot list resource "deployments" in API group "apps" in the namespace "test"
切换回管理员账号
# kubectl config use-context kubernetes-admin@kubernetes

7、ChusterRole

ClusterRole可以对集群范围内资源、跨namespace的范围资源、非资源类型进行授权

cat clusterole.yml

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: devuser-clusterrole #名称自定义,无需指定名称空间
  
rules:
  - apiGroups: [""] #支持的API组列表,""空字符串,表示核心API群
    resources: ["pods","deployments"] #支持的资源对象列表
    verbs: ["get", "list", "watch", "create", "update","patch", "delete"] #允许对资源对象的操作方法列表

创建ClusterRole

# kubectl create -f clusterole.yml
# kubectl get clusterrole | grep deployment
deployment-clusterrole

8、ClusterRoleBinding

ClusterRoleBinding可对于clusterrole(集群角色)与目标对象进行绑定

一种很常用的做法是,集群管理员为集群范围预定义好一个ClusterRole,然后通过RoleBinding在多个命名空间中重复使用这些ClusterRole,所以同一个ClusterRole只能读取某一个空间内的资源

cat devuser-clusterrolebinding.yml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: clusterrole-rolebinding

roleRef: #指向的角色
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole #角色类型
  name: devuser-clusterrole #角色名称(提前创建好)
  
subjects: #定义对象
- kind: User #对象类型(User、Groups、ServiceAccount)
  name: devuser #对象名称(提前创建好)
  namespace: test #须名称空间

创建ClusterRoleBinding

# kubectl create -f clusterrole-binding.yml
# kubectl get clusterrolebinding | grep clusterrole-rolebinding
clusterrole-rolebinding

切换devuser用户检验权限

# kubectl config get-contexts
# kubectl config use-context devuser@kubernetes
# kubectl get pod -n test
# kubectl get pod -n kube-system
切换回管理员账号
# kubectl config use-context kubernetes-admin@kubernetes

clusterrole与ServiceAccount绑定

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-rolebinding

roleRef: #指向的角色
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole #角色类型
  name: devuser-clusterrole #角色名称(提前创建好)
  
subjects: #定义对象
- kind: ServiceAccount #对象类型(User、Groups、ServiceAccount)
  name: admin #对象名称(提前创建好)
  namespace: test #须名称空间

准入控制(Admission Control)

准入控制是请求的最后一个步骤,准入控制有许多内置的模块,可以作用于对象的 “CREATE”、“UPDATE”、“DELETE”、“CONNECT” 四个阶段。在这一过程中,如果任一准入控制模块拒绝,那么请求立刻被拒绝。一旦请求通过所有的准入控制器后就会写入对象存储中。

**总结:**认证解决的问题是识别用户的身份,鉴权是为了解决用户有哪些权限,准入控制是作用于 k8s 中的对象,通过合理的权限管理,能够保证系统的安全可靠,准入控制通常情况下可以不用。

十三、K8S数据存储

由于容器的生命周期不稳定,可能随时被创建与销毁,如果容器被销毁后,在容器中产生的数据也会被清除,如果需要对容器内的数据实现持久化保存,我们需要将容器内的数据与pod分离,将数据放在专门的存储卷上

1、存储卷的分类

kubernetes支持的存储卷类型非常丰富,使用下面的命令查看

# kubectl explain pod.spec.volumes
  • 或者参考: https://kubernetes.io/docs/concepts/storage/

K8s支持的存储类型大体分为如下几类:

  • 本地存储卷
    • emptyDir(空目录临时存储):pod删除,数据也会被清除, 用于数据的临时存储
    • hostPath:宿主机目录映射(本地存储卷),pod删除,目录中的数据不会被清楚,适合数据的永久保存
  • 网络存储卷
    • NAS网络附加存储: nfs等分布式网络附加存储: glusterfs,cephfs,rbd(chph中的存储类型),cinder(OpenStack中的存储类型)等
    • SAN块存储: iscsi,FC等
    • 云存储: aws,azurefifile等

2、本地存储

2.1、EmptyDir

EmptyDir是最基础的存储类型,一个EmptyDir就是主机上的一个空目录

EmptyDir是在Pod被分配到Node节点时创建的,它的初始内容为空,并且无需指定宿主机上对应的目录文件,应为k8s会自动分配一个空目录,当Pod销毁时,EmptyDir中的数据也会被永久删除

EmptyDir用途如下:

  • 临时存储空间,例如用于某些应用程序运行时所需要的临时目录,且无需永久保留
  • 同一个Pod中容器需要从另一个容器中获取数据的目录(多容器间共享数据)

案例:通过创建一个nginx的Pod并使用emptydir作为数据的临时存储

[root@master01 ~]# vim emptydir_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
  
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
      
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
    spec:
      volumes: 声明volume存储卷
      - name: nginx-logs 定义volume卷名称
        emptyDir: {} 类型为emptyDir,{}表示空目录
        
      containers:
      - name: nginx
        image: nginx:1.17.0 #指定镜像
        ports: #定义端口
        - containerPort: 80 #端口
        
        volumeMounts:
        - name: nginx-logs 指定挂载的volume名称
          mountPath: /var/log/nginx 容器内挂载点目录
          
创建Pod
[root@master01 ~]# kubectl create -f emptydir_nginx.yml

查看Pod信息
[root@master01 ~]# kubectl get pod -n test -o wide deploy-nginx-6765b8f99c-wwzj6 2/2 Running 0
16m 10.244.5.42 worker01

可以通过find命令在对应节点中搜索存储卷目录的所在位置
[root@worker01 ~]# find /var/lib/kubelet/pods/ -namenginx-logs

访问nginx
[root@master01 ~]# curl 10.244.5.42

删除Pod
[root@master01 ~]# kubectl delete -f emptydir_nginx.yml

总结:EmptyDir存储方式不会永久保存数据,应为EmptyDir的生命周期是跟据Pod的生命周期是一样的,它会随着Pod的结束而销毁,如果想简单的将数据持久化到集群主机中,可以选择用HostPath。

2.2、HostPath

HostPath是将Node节点中一个实际目录挂载到Pod中,以供容器使用,这样的设计可以保证Pod销毁了,但是数据仍然可以保存在宿主机上,实现数据永久保存

案例:创建nginx,并通过hostPath存储卷方式对nginx实现数据持久化保存。

[root@master01 ~]# vim hostpath_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
      
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
        
    spec:
      volumes: 声明volume存储卷
      - name: nginx-html 定义volume名称
        hostPath: 类型hostPath
        type: DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
        path: /nginx/html 指定node节点目录(存放页面)
        
      - name: nginx-logs 定义volume名称
        hostPath: 类型hostPath
        type: DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
        path: /nginx/logs 指定node节点目录(存放日志)
        
      containers:
      - name: nginx
        image: nginx:1.17.0 #指定镜像
        ports: #定义端口
        - containerPort: 80 #端口
        
        volumeMounts:
        - name: nginx-html 指定挂载的volume名称
          mountPath: /usr/share/nginx/html 容器内挂载点目录
        - name: nginx-logs 指定挂载的volume名称
          mountPath: /var/log/nginx 容器内挂载点目录
        
关于 hostPath的type属性可用值说明:
	DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
	Directory 目录必须存在
	FileOrcreate 文件存在就使用,不存在就先创建后使用
	File 文件必须存在
	Socket 套接字必须存在
	CharDevice 字符设备必须存在
	BlockDevice 块设备必须存在
创建Pod
[root@master01 ~]# kubectl create -f hostpath_nginx.yml
查看Pod详细信息
[root@master01 ~]# kubectl get pod -n test -o wide 
deploy-nginx-8578d555c9-np9gk 1/1 Running 0 6m46s 10.244.5.48 worker01

查看worker01节点的hostPath目录
[root@worker01 ~]# ls /nginx
html
创建index.html文件进行访问测试
[root@worker01 ~]# echo hello > /nginx/html/index.html
通过Pod访问
[root@master01 ~]# curl 10.244.5.48
删除Pod验证数据持久化
[root@master01 ~]# kubectl delete -f hostpath_nginx.yml

总结:HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,那么数据卷并不会转移到其他的节点,为了解决以上的问题,可以使用网络文件存储系统,比较常见的有NFS、glusterfs等。

3、网络存储

3.1、NFS

NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连到NFS系统上,这样无论Pod在节点上怎么转移,只要该节点跟NFS对接没问题,数据就可以成功访问。

部署NFS服务端

单独准备一台服务器部署NFS

安装nfs-utils
[root@k8s-nfs01 ~]# yum -y install nfs-utils

创建共享目录
[root@k8s-nfs01 ~]# mkdir -p /k8s-nfs/nginx/html
[root@k8s-nfs01 ~]# mkdir /k8s-nfs/nginx/logs

共享目录
[root@k8s-nfs01 ~]# vim /etc/exports
/k8s-nfs/nginx/html 192.168.0.0/24(rw,no_root_squash)
/k8s-nfs/nginx/logs 192.168.0.0/24(rw,no_root_squash)

启动nfs服务&&设置服务随机自启
[root@k8s-nfs01 ~]# systemctl start nfs && systemctl enable nfs

NFS客户端

在集群worker节点上都安装nfs客户端工具,不需要启动服务,这样worker节点才可以驱动nfs设备

# yum -y install nfs-utils

查看共享资源
# showmount -e 192.168.0.15
Export list for 192.168.0.15:
/k8s-nfs/nginx/logs 192.168.0.0/24
/k8s-nfs/nginx/html 192.168.0.0/24

案例:创建Pod,并通过NFS存储卷方式对nginx实现数据持久化保存。

# cat vim nfs_nginx.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx #pod的标签
        
    spec:
      volumes: 声明volume存储卷
      - name: volume-ngx-html 定义volume名称
        nfs: 类型nfs
          server: 192.168.0.15 NFS服务器地址
          path: /k8s-nfs/nginx/html NFS共享目录
      - name: volume-ngx-logs 定义volume名称
        nfs: 类型nfs
          server: 192.168.0.15 NFS服务器地址
          path: /k8s-nfs/nginx/logs NFS共享目录
      containers:
      - name: nginx
        image: nginx:1.18.0 #指定镜像
        ports: #定义端口
        - containerPort: 80 #端口
        
        volumeMounts:
        - name: volume-ngx-html 指定挂载的volume名称
            mountPath: /usr/share/nginx/html 容器内挂载点目录
        - name: volume-ngx-logs 指定挂载的volume名称
            mountPath: /var/log/nginx 容器内挂载点目录
创建Pod
[root@master01 ~]# kubectl create -f nfs_nginx.yml
查看Pod详细信息
[root@master01 ~]# kubectl describe pod nfs-nginx-5c8699644d-mv6bl -n test
...
	Mounts:
		/usr/share/nginx/html from volume-html (rw)
		/var/log/nginx from volume-logs (rw)
...
Volumes:
  volume-html:
    Type: NFS (an NFS mount that lasts the lifetime of a pod)
	Server: 192.168.0.15
	Path: /k8s-nfs/nginx/html
	ReadOnly: false
  volume-logs:
	Type: NFS (an NFS mount that lasts the lifetime of a pod)
	Server: 192.168.0.15
	Path: /k8s-nfs/nginx/logs
	ReadOnly: false
	
验证nfs共享目录
[root@k8s-nfs01 ~]# ls /k8s-nfs/nginx/logs/
access.log error.log

删除Pod
[root@master01 ~]# kubectl delete -f nfs_nginx.yml

验证数据持久化
[root@k8s-nfs01 ~]# ls /k8s-nfs/nginx/logs/
access.log error.log

3.2、PV 与 PVC

经过前面的NFS存储已经可以实现数据的持久化保存,而k8s为了能够屏蔽底层的存储细节,方便用户使用,k8s引入了PV和PVC的存储方式

  • PV(Persistent Volume 存储卷):可以理解为是一个网络存储,就是一个实实在在的存储数据的地方,比如NFS、iSCSI、Ceph和云提供商指定的存储系统。

若严格来说,PV是k8s里面的一个概念,它本身不是存储,只不过是创建pv的资源清单文件中指定了网络存储的地址,同时也指定了一些存储的参数。

  • PVC(Persistent Volume Claim 存储卷声明): 可以理解为Pod对所需存储空间的申请方式,也就是说PVC为其Pod寻找一个合适的PV进行绑定,绑定之后就可以使用PV提供的存储资源。

PV资源清单文件介绍

apiVersion: v1
kind: PersistentVolume
metadata:
  name:
spec:
  nfs: 存储类型,与底层真正存储对应,如:nfs
  capacity: 存储能力,目前只支持存储空间的设置
    storage: 4Gi 存储空间
  accessModes: 访问模式
  persistentVolumeReclaimPolicy: 回收策略

accessModes(访问模式):用于描述用户应用对存储资源的访问权限,访问权限包含以下几种方式:

  • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
  • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
  • ReadWriteMany(RWX):读写权限,可以被多个节点挂载

注意事项:底层不同的存储类型可能支持的访问模式也不同

persistentVolumeReclaimPolicy(回收策略):当PV不再被PVC使用之后,对其PV内的数据处理方式,目前支持三种策略

  • Retain(保留):保留数据,需要管理员手工清理数据
  • Recycle(回收):清除PV中的数据,效果相当于执行rm -rf
  • Delete(删除):与PV相连的后端存储完成volume的删除操作,当然这常见于云服务商的存储服务

注意事项:底层不同的存储类型可能支持的回收策略也不同

案例:使用NFS作为底层存储,并通过PV的方式实现数据持久化

创建共享目录
[root@k8s-nfs01 ~]# mkdir -p /k8s-nfs/pv01-mysql

共享目录
[root@k8s-nfs01 ~]# vim /etc/exports
/k8s-nfs/pv01-mysql 192.168.0.0/24(rw,no_root_squash)

重启nfs服务
[root@k8s-nfs01 ~]# systemctl restart nfs
3.2.1、PV 应用案例

案例:创建一个4G 的 PV 存储卷,并使用NFS作为后端存储。

[root@master01 ~]# vim pv01-mysql.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01-mysql
  
spec:
  capacity: #存储能力,目前只支持存储空间的设置
    storage: 4Gi #存储空间
  accessModes: #访问模式
  - ReadWriteMany #读写权限,可以被多个节点挂载
  persistentVolumeReclaimPolicy: Retain #回收策略为保留
  nfs: #存储类型
    path: /k8s-nfs/pv01-mysql #挂载路径
    server: 192.168.0.15 #nfs服务器地址
    
#提示:PV是全局资源,无需指定命名空间

创建pv
[root@master01 ~]# kubectl create -f pv01-mysql.yml

查看pv详细信息
[root@master01 ~]# kubectl get pv -o wide
PV状态:一个PV的生命周期中,可能会处于4种不同的阶段

1. Avallable(可用):表示可用状态,还未被任何的PVC绑定
2. Bound(已绑定):表示PV已经被PVC绑定
3. Released(已释放):表示PVC被删除,但是资源还未被集群重新声明
4. Falled(失败):表示该PV的自动回收失败
3.2.2、PVC 应用案例

PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息,PVC清单文件介绍:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
  namespace: test
  
spec:
  accessModes: 访问模式
  selector: 标签选择器,采用标签对PV选择
  storageClassName: 存储类别
  resources: 资源
    requests: 请求
      storage: 资源大小

案例:创建一个PVC,并绑定pv-mysql存储卷

[root@master01 ~]# vim pvc-mysql.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-mysql
  namespace: test
spec:
  accessModes: #访问模式,访问模式要与PV模式相同,否则绑定不上
  - ReadWriteMany #读写权限,可以被多个节点挂载
  resources: #请求
    requests: #资源
      storage: 4Gi #资源大小,在绑定PV时,按照申请资源大小选择符合的PV,如果超出PV空间范围,则无法绑定
      
#PVC是局部资源,可指定命名空间

创建pvc
[root@master01 ~]# kubectl create -f pvc_mysql.yml

查看pvc信息
[root@master ~]# kubectl get pvc -n test

查看pv信息
[root@master ~]# kubectl get pv

案例:创建MySQL并挂载PVC实现数据持久化。

提示:需要提前在集群节点安装好nfs-utils

[root@master01 ~]# vim pv-pvc_mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-mysql
  namespace: test
  
spec:
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-mysql #匹配pod的标签(表示deploy管理带有此标签的Pod)
      
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-mysql #pod的标签
    spec:
      volumes: 声明volume存储卷
      - name: mysql-data 定义volume名称
        persistentVolumeClaim: 类型为PVC
          claimName: pvc-mysql PVC名称(与前边创建的PVC名称一致)
          readOnly: false 访问模式,false为读写,true为只读
          
      containers:
      - name: mysql
        image: mysql:5.7 #镜像版本
        ports: #定义端口
        - containerPort: 3306 #端口
        env: #定义环境变量
        - name: "MYSQL_ROOT_PASSWORD" #变量名称(必须为数组类型)
          value: "123456" #值
          
        volumeMounts:
        - name: mysql-data 指定挂载的volume名称,与上述volume名称一致
          mountPath: /var/lib/mysql 容器内挂载点目录创建pod
          
[root@master01 ~]# kubectl create -f pv-pvc_mysql.yml

查看pod信息
[root@master01 ~]# kubectl get po -n test

查看NFS共享存储路径
[root@k8s-nfs01 ~]# ls /k8s-nfs/pv01-mysql/

删除pod、pvc、pv
[root@master01 ~]# kubectl delete -f pv01-mysql.yml
[root@master01 ~]# kubectl delete -f pvc_mysql.yml
[root@master01 ~]# kubectl delete -f pv_mysql.yml

总结:

  1. pv资源供应:管理员手动创建底层存储和PV

  2. pvc资源绑定:用户创建PVC,k8s负责根据PVC的声明去寻找PV,并绑定在用户定义好的PVC之后,系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的,一旦找到,就将PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC,如果找不到,PVC一直处于Pending状态,直到管理员创建了一个符合要求的PV,PV一旦绑定到某个PVC上,就会被这个PVC独占,不能在与其他的PVC进行绑定

  3. 资源使用:用户可在pod中像volume一样使用PVC,将PVC挂载到容器的某个路径进行使用

  4. 资源释放:当存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定,应为之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用

  5. 资源回收:k8s根据PV设置的回收策略进行资源的回收

3.3、k8s存储类StorageClass

上面介绍的PV和PVC模式都是需要先创建好PV,然后定义好PVC和pv进行一对一的Bond,但是如果PVC请求成千上万,那么就需要创建成千上万的PV,对于运维人员来说维护成本很高,Kubernetes提供一种自动创建PV的机制,叫StorageClass,它的作用就是创建PV的模板。k8s集群管理员

通过创建storageclass可以动态生成一个存储卷pv供k8s pvc使用。

查看定义的storageclass需要的字段

# kubectl explain storageclass
apiVersion: storage.k8s.io/v1 #资源版本
kind: StorageClass #资源类型
metadata:
  name: nfs-client #资源名称
provisioner: nfs-provisioner #定义存储的供应者(名称自定义)
reclaimPolicy: Retain #回收策略,保留数据,需要管理员手工清理数据
allowVolumeExpansion: true #允许卷扩展,将此功能设置为true时,允许用户通过编辑相应的 PVC 对象来调整卷大小(不能用于缩小卷)但是,只有云端存储才支持此参数。
volumeBindingMode: Immediate #绑定模式为立即绑定,一旦创建了PVC,就会立即发生卷绑定和动态配置

provisioner(存储的供应者)以NFS为例,要想使用NFS提供真正的存储资源,我们需一个nfs-client的自动装载程序,称之为provisioner,这个程序会使用我们已经配置好的NFS服务器自动创建持久卷,也就是自动帮我们创建PV。
如果是其他存储类型可以参考https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#aws-ebs

十四、K8S 日志收集ELK

常见的日志收集方案

ELK简介:ELK是三个开源软件的缩写,分别表示:ElasticSearchLogstashKibana

  • Elasticsearch:是个开源分布式搜索引擎数据库,提供搜集、分析、存储数据三大功能。
  • Logstash:主要是用来做日志的分析、过滤等处理工作。
  • Kibana:可以为 Logstash 和 ElasticSearch 提供的日志提供友好的Web 界面,可以帮助汇总、分析和搜索重要数据日志。
  • 新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,适合于在各个服务器上搜集日志后传输给Logstash。

传统服务日志收集与K8s服务日志收集区别:

  • 传统日志收集:传统服务部署在固定的服务器,而日志也固定服务器中的具体目录中,即便服务器重启,应用依然在固定的节点,对日志收集系统来讲,也不需要重新指定日志的所在位置。
  • K8s日志收集:在K8s集群中,服务通常不会固定在某一个节点,如果服务重启、弹性伸缩,那么服务可能会漂移到其他的节点,所以对于K8s中日志的收集与传统的方式不太一样。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fluentd这种需要我们在每个 Pod 中都附带一个Agent容器来进行本 Pod内部容器的日志采集,

一般采用共享卷的方式,但是对于这一种模式来说,很明显的一个问题就是占用的资源比较多,尤其是在集群规模比较大的情况下,或者说单个节点上Pod特别多的情况下,它会占用过多的系统资源,同时也对日志存储后端占用过多的连接数。当我们的集群规模越大,这种部署模式引发的潜在问题就越大。

1、破解利器Log-Pilot

1.1、特性

  • 轻量级:Log-Pilot采用节点模式(每个Node节点仅会部署一个Agent)进行日志采集,对比与上述flfluentd(每个Pod中部署一个Agent)更加的节约资源,同样在集群规模比较大的情况下表现出的优势越明显。
  • 自动检测:Log-Pilot 能够自动感知宿主机上容器的创建删除事件,进而动态配置容器日志采集配置文件。
  • 句柄保持机制:Log-Pilot 内部会实时跟踪日志采集偏移量,然后维持日志文件信息与偏移量的映射关系,最后定期地持久化到磁盘中。采用偏移量的方式我们可以避免日志采集丢失和重复的问题,同时即使当采集工具宕掉再起来,它可以通过加载持久化在磁盘上的元数据信息,然后从指的日志偏移位置上继续采集日志。

1.2、环境准备

本案例在K8s集群内部署日志收集系统ELK(节点内存至少6G)。

创建 Service Account

创建es的Service Account,ServiceAccount在K8s中可用于存储服务的账号信息,用于给运行在Pod里面的进程提供必要的身份证明。

[root@master01 ~]# kubectl create sa es-admin -n kube-system
[root@master01 ~]# kubectl create clusterrolebinding es-admin --clusterrole=cluster-admin --serviceaccount=kube-system:es-admin
当serviceaccout创建时K8s会默认创建对应的secret用于存储账号的token信息
[root@master01 ~]# kubectl get secrets -n kube-system | grep es-admin

2、部署ES集群

es集群采用StatefulSet控制器部署,StatefulSet本质上是Deployment的一种变体,用于部署有状态服务,它所管理的Pod拥有固定的Pod名称,启停顺序。

[root@master01 logs]# kubectl create -f elasticsearch.yaml

查看StatefulSet信息(缩写:sts)
[root@master01 logs]# kubectl get sts -n kube-system

查看es的Pod
[root@master01 ~]# kubectl get pod -n kube-system -o wide | grep elastic

查看es的svc端口
[root@master01 logs]# kubectl get svc -n kube-system
elasticsearch-0 1/1 Running 0 22m
elasticsearch-1 1/1 Running 0 22m
elasticsearch-2 1/1 Running 0 21m

3、部署 Log-Pilot

为了保证集群每个节点都能够采集到日志信息,Log Pilot采用DaemonSet控制器创建,DaemonSet可以保证集群的每个节点都存在一个相同的副本。

[root@master01 logs]# kubectl apply -f log-pilot.yaml
[root@master01 ~]# kubectl get pod -n kube-system | grep log-pilot
log-pilot-c4kvk 1/1 Running 0 2m32s
log-pilot-s78h8 1/1 Running 0 2m32s
log-pilot-xlclz 1/1 Running 0 2m32s
log-pilot-xzwps 1/1 Running 0 2m32s

4、部署 kibana

kibana提供web页面展示,采用Deployment控制器部署(只需要部署一个即可)。

[root@master01 logs]# kubectl apply -f kibana.yaml
[root@master01 logs]# kubectl get deploy -n kube-system kibana 1/1 1 1 82s
[root@master01 logs]# kubectl get ing -n kube-system
NAME CLASS HOSTS ADDRESS PORTS AGE
kibana <none> www.kibana.com 192.168.0.13 80 4m2s

配置域名解析:C:\Windows\System32\drivers\etc

192.168.0.13 www.kibana.com

访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问

查看ingress-nginx暴露的端口
[root@master01 logs]# kubectl get svc -n ingress-nginx 
NAME TYPE CLUSTER-IP EXTERNAL-IP
ingress-nginx-controller NodePort 10.111.226.197 <none> 80:31681/TCP,443:31150/TCP 22m

访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口

访问: http://www.kibana.com:31681/
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

部署应用并采集日志

[root@master01 ~]# vim elk.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      #容器
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
        # 环境变量
        env:
        - name: aliyun_logs_nginx #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
          value: "stdout"
        - name: aliyun_logs_nginxlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
          value: "/var/log/nginx/*"
        volumeMounts:
        - mountPath: /var/log/nginx/
          name: nginxlogs
      #数据存储类型   
      volumes:
      - name: nginxlogs
        emptyDir: {}
        
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  selector:
    app: deploy-nginx
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 80
    targetPort: 80
      
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-tomcat
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-tomcat
  template:
    metadata:
      labels:
        app: deploy-tomcat
  spec:
    containers:
    - name: tomcat
      image: tomcat:8.5-jre10-slim
      ports:
      - containerPort: 8080
      # 环境变量
      env:
      - name: aliyun_logs_tomcat #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
        value: "stdout"
      - name: aliyun_logs_tomcatlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
        value: "/usr/local/tomcat/logs/*"
      # 数据挂载 
      volumeMounts:
      - mountPath: /usr/local/tomcat/logs
        name: tomcatlogs
    #数据存储类型    
    volumes:
    - name: tomcatlogs
      emptyDir: {}
      
---
apiVersion: v1
kind: Service
metadata:
  name: svc-tomcat
  namespace: test
spec:
  selector:
    app: deploy-tomcat
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 8080
    targetPort: 8080
    
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-http #自定义ingress名称
  namespace: test
  annotations:
  ingressclass.kubernetes.io/is-default-class: "true"
  kubernetes.io/ingress.class: nginx #注释名称需为nginx(不可省略)
spec:
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-nginx #对应上面创建的service名称
            port:
              number: 80 #service端口
  - host: www.tomcat.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-tomcat #对应上面创建的service名称
            port:
              number: 8080 #service端口

创建Pod
[root@master01 ~]# kubectl create -f elk.yml

h`:主要是用来做日志的分析、过滤等处理工作。

  • Kibana:可以为 Logstash 和 ElasticSearch 提供的日志提供友好的Web 界面,可以帮助汇总、分析和搜索重要数据日志。
  • 新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,适合于在各个服务器上搜集日志后传输给Logstash。

传统服务日志收集与K8s服务日志收集区别:

  • 传统日志收集:传统服务部署在固定的服务器,而日志也固定服务器中的具体目录中,即便服务器重启,应用依然在固定的节点,对日志收集系统来讲,也不需要重新指定日志的所在位置。
  • K8s日志收集:在K8s集群中,服务通常不会固定在某一个节点,如果服务重启、弹性伸缩,那么服务可能会漂移到其他的节点,所以对于K8s中日志的收集与传统的方式不太一样。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fluentd这种需要我们在每个 Pod 中都附带一个Agent容器来进行本 Pod内部容器的日志采集,

一般采用共享卷的方式,但是对于这一种模式来说,很明显的一个问题就是占用的资源比较多,尤其是在集群规模比较大的情况下,或者说单个节点上Pod特别多的情况下,它会占用过多的系统资源,同时也对日志存储后端占用过多的连接数。当我们的集群规模越大,这种部署模式引发的潜在问题就越大。

1、破解利器Log-Pilot

1.1、特性

  • 轻量级:Log-Pilot采用节点模式(每个Node节点仅会部署一个Agent)进行日志采集,对比与上述flfluentd(每个Pod中部署一个Agent)更加的节约资源,同样在集群规模比较大的情况下表现出的优势越明显。
  • 自动检测:Log-Pilot 能够自动感知宿主机上容器的创建删除事件,进而动态配置容器日志采集配置文件。
  • 句柄保持机制:Log-Pilot 内部会实时跟踪日志采集偏移量,然后维持日志文件信息与偏移量的映射关系,最后定期地持久化到磁盘中。采用偏移量的方式我们可以避免日志采集丢失和重复的问题,同时即使当采集工具宕掉再起来,它可以通过加载持久化在磁盘上的元数据信息,然后从指的日志偏移位置上继续采集日志。

1.2、环境准备

本案例在K8s集群内部署日志收集系统ELK(节点内存至少6G)。

创建 Service Account

创建es的Service Account,ServiceAccount在K8s中可用于存储服务的账号信息,用于给运行在Pod里面的进程提供必要的身份证明。

[root@master01 ~]# kubectl create sa es-admin -n kube-system
[root@master01 ~]# kubectl create clusterrolebinding es-admin --clusterrole=cluster-admin --serviceaccount=kube-system:es-admin
当serviceaccout创建时K8s会默认创建对应的secret用于存储账号的token信息
[root@master01 ~]# kubectl get secrets -n kube-system | grep es-admin

2、部署ES集群

es集群采用StatefulSet控制器部署,StatefulSet本质上是Deployment的一种变体,用于部署有状态服务,它所管理的Pod拥有固定的Pod名称,启停顺序。

[root@master01 logs]# kubectl create -f elasticsearch.yaml

查看StatefulSet信息(缩写:sts)
[root@master01 logs]# kubectl get sts -n kube-system

查看es的Pod
[root@master01 ~]# kubectl get pod -n kube-system -o wide | grep elastic

查看es的svc端口
[root@master01 logs]# kubectl get svc -n kube-system
elasticsearch-0 1/1 Running 0 22m
elasticsearch-1 1/1 Running 0 22m
elasticsearch-2 1/1 Running 0 21m

3、部署 Log-Pilot

为了保证集群每个节点都能够采集到日志信息,Log Pilot采用DaemonSet控制器创建,DaemonSet可以保证集群的每个节点都存在一个相同的副本。

[root@master01 logs]# kubectl apply -f log-pilot.yaml
[root@master01 ~]# kubectl get pod -n kube-system | grep log-pilot
log-pilot-c4kvk 1/1 Running 0 2m32s
log-pilot-s78h8 1/1 Running 0 2m32s
log-pilot-xlclz 1/1 Running 0 2m32s
log-pilot-xzwps 1/1 Running 0 2m32s

4、部署 kibana

kibana提供web页面展示,采用Deployment控制器部署(只需要部署一个即可)。

[root@master01 logs]# kubectl apply -f kibana.yaml
[root@master01 logs]# kubectl get deploy -n kube-system kibana 1/1 1 1 82s
[root@master01 logs]# kubectl get ing -n kube-system
NAME CLASS HOSTS ADDRESS PORTS AGE
kibana <none> www.kibana.com 192.168.0.13 80 4m2s

配置域名解析:C:\Windows\System32\drivers\etc

192.168.0.13 www.kibana.com

访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问

查看ingress-nginx暴露的端口
[root@master01 logs]# kubectl get svc -n ingress-nginx 
NAME TYPE CLUSTER-IP EXTERNAL-IP
ingress-nginx-controller NodePort 10.111.226.197 <none> 80:31681/TCP,443:31150/TCP 22m

访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口

访问: http://www.kibana.com:31681/
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

部署应用并采集日志

[root@master01 ~]# vim elk.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      #容器
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
        # 环境变量
        env:
        - name: aliyun_logs_nginx #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
          value: "stdout"
        - name: aliyun_logs_nginxlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
          value: "/var/log/nginx/*"
        volumeMounts:
        - mountPath: /var/log/nginx/
          name: nginxlogs
      #数据存储类型   
      volumes:
      - name: nginxlogs
        emptyDir: {}
        
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  selector:
    app: deploy-nginx
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 80
    targetPort: 80
      
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-tomcat
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-tomcat
  template:
    metadata:
      labels:
        app: deploy-tomcat
  spec:
    containers:
    - name: tomcat
      image: tomcat:8.5-jre10-slim
      ports:
      - containerPort: 8080
      # 环境变量
      env:
      - name: aliyun_logs_tomcat #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
        value: "stdout"
      - name: aliyun_logs_tomcatlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
        value: "/usr/local/tomcat/logs/*"
      # 数据挂载 
      volumeMounts:
      - mountPath: /usr/local/tomcat/logs
        name: tomcatlogs
    #数据存储类型    
    volumes:
    - name: tomcatlogs
      emptyDir: {}
      
---
apiVersion: v1
kind: Service
metadata:
  name: svc-tomcat
  namespace: test
spec:
  selector:
    app: deploy-tomcat
  clusterIP: None
  type: ClusterIP #service类型
  ports:
  - port: 8080
    targetPort: 8080
    
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-http #自定义ingress名称
  namespace: test
  annotations:
  ingressclass.kubernetes.io/is-default-class: "true"
  kubernetes.io/ingress.class: nginx #注释名称需为nginx(不可省略)
spec:
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-nginx #对应上面创建的service名称
            port:
              number: 80 #service端口
  - host: www.tomcat.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径
        backend: #定义后端引用的服务
          service: #关联service
            name: svc-tomcat #对应上面创建的service名称
            port:
              number: 8080 #service端口

创建Pod
[root@master01 ~]# kubectl create -f elk.yml
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值