原创

k8s基础

kubernetes

一、k8s概念

1.Kubernetes介绍

Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。

Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。k8s 这个缩写是因为 k 和 s 之间有八个字符的关系。 Google 在 2014 年开源了 Kubernetes 项目。

2.为什么需要k8s?
1.应用部署的三大阶段
  • 传统部署时代

    • 早期,各个组织是在物理服务器上运行应用程序。 由于无法限制在物理服务器中运行的应用程序资源使用,因此会导致资源分配问题。 例如,如果在同一台物理服务器上运行多个应用程序, 则可能会出现一个应用程序占用大部分资源的情况,而导致其他应用程序的性能下降。 一种解决方案是将每个应用程序都运行在不同的物理服务器上, 但是当某个应用程序资源利用率不高时,剩余资源无法被分配给其他应用程序, 而且维护许多物理服务器的成本很高。
  • 虚拟化部署时代

    • 因此,虚拟化技术被引入了。虚拟化技术允许你在单个物理服务器的 CPU 上运行多台虚拟机(VM)。 虚拟化能使应用程序在不同 VM 之间被彼此隔离,且能提供一定程度的安全性, 因为一个应用程序的信息不能被另一应用程序随意访问。
    • 虚拟化技术能够更好地利用物理服务器的资源,并且因为可轻松地添加或更新应用程序, 而因此可以具有更高的可扩缩性,以及降低硬件成本等等的好处。 通过虚拟化,你可以将一组物理资源呈现为可丢弃的虚拟机集群。
    • 每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
  • 容器部署时代

    • 容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。

      容器因具有许多优势而变得流行起来,例如:

    • 敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。

    • 持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性), 提供可靠且频繁的容器镜像构建和部署。

    • 关注开发与运维的分离:在构建、发布时创建应用程序容器镜像,而不是在部署时, 从而将应用程序与基础架构分离。

    • 可观察性:不仅可以显示 OS 级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。

    • 跨开发、测试和生产的环境一致性:在笔记本计算机上也可以和在云中运行一样的应用程序。

    • 跨云和操作系统发行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方运行。

    • 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。

    • 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分, 并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。

    • 资源隔离:可预测的应用程序性能。

    • 资源利用:高效率和高密度。

2.k8s特点
  • 服务发现和负载均衡
    • Kubernetes 可以使用 DNS 名称或自己的 IP 地址来暴露容器。 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。
  • 存储编排
    • Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。
  • 自动部署和回滚
    • 你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
  • 自动完成装箱计算
    • 你为 Kubernetes 提供许多节点组成的集群,在这个集群上运行容器化的任务。 你告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源
  • 自我修复
    • Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。
  • 密钥与配置管理
    • Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
  • 批处理执行
    • 除了服务外,Kubernetes 还可以管理你的批处理和 CI(持续集成)工作负载,如有需要,可以替换失败的容器。
  • 水平扩缩
    • 使用简单的命令、用户界面或根据 CPU 使用率自动对你的应用进行扩缩。
  • IPv4/IPv6 双栈
    • 为 Pod(容器组)和 Service(服务)分配 IPv4 和 IPv6 地址。
  • 为可扩展性设计
    • 在不改变上游源代码的情况下为你的 Kubernetes 集群添加功能
3.k8s组件介绍

1721877321427

1.控制面板组件
  • kube-apiserver
    • 所有服务访问统一入口,负责处理接受请求的工作
  • kube-crontroller-manager
    • 维持副本期望数目
  • cloud-controller-manager
    • 嵌入了特定于云平台的控制逻辑。 云控制器管理器与 kube-controller-manager 类似
  • kube-schedule
    • 选择合适的节点进行分配任务
  • etcd
    • 用作 Kubernetes 所有集群数据的后台数据库。
2.节点组件
  • Kubelet
    • 和容器交互
  • kube-proxy
    • 负责写入规则,实现服务映射
  • Container Runtime
    • 它负责管理 Kubernetes 环境中容器的执行和生命周期。
3.其他组件
kubectl:用来与集群通信的命令行工具
kubeadm:用来初始化集群的指令。
coredns:创建集群中域名ip对应关系解析
dashboard:提供B/S结构访问体系
ingress:提供七层代理
federation:提供一个人可以跨集群中心多k8s统一管理功能
prometheus:提供k8s集群监控能力

二、k8s前置配置

1.主机硬件配置说明
序号主机名IP地址角色系统版本硬件配置
1k8s-master192.168.47.10管理节点centos72CPU/4G内存/30G存储
2k8s-node1192.168.47.11工作节点centos72CPU/4G内存/30G存储
3k8s-node2192.168.47.12工作节点centos72CPU/4G内存/30G存储
2.主机名配置
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-node1
hostnamectl set-hostname k8s-node2
3.主机名与IP地址解析
cat >> /etc/hosts << EOF
192.168.47.10 k8s-master
192.168.47.11 k8s-node1
192.168.47.12 k8s-node2
EOF
4.安装工具依赖包
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git lrzsz
5.关闭selinux
setenforce 0
sed -ri 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
#关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
6.关闭swap分区

kubernetes要求必须关闭swap分区

swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab
7.主机系统时间同步
# 安装软件
yum -y install ntpdate
# 制定时间同步计划任务
crontab -e
0 */1 * * * ntpdate time1.aliyun.com
8.内核升级

升级原因:CentOS 7.x 系统自带的 3.10.x 内核存在一些 Bugs,导致运行的 Docker、Kubernetes 不稳定,配置后重启电脑。

#查看内核版本
[root@localhost ~]# uname -r
3.10.0-1062.el7.x86_64
#下载
yum -y install http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
#安装
yum --enablerepo=elrepo-kernel install -y kernel-lt
#设置内核
grub2-set-default 'CentOS Linux (5.4.251-1.el7.elrepo.x86_64) 7 (Core)'
9.k8s内核优化

转发IPv4并让iptables看到桥接流量

#模块加载,相当于开起了一个透明防火墙,不加载会报错
modprobe br_netfilter
#查看是否加在
lsmod | egrep 'br_netfilter | overlay'
#写入规则到文本,为了数据转发,路由
cat <<EOF > /etc/sysctl.d/kubernetes.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
#执行 应用 sysctl 参数而不重新启动
sysctl --system 或者 sysctl -p /etc/sysctl.d/kubernetes.conf

解释

#内核参数说明
net.ipv4.ip_forward = 1 #默认为0,说明禁止进行IP转发;如果是1,则说明IP转发功能已经打开。
net.bridge.bridge-nf-call-iptables = 1 #二层的网桥在转发包时也会被iptables的FORWARD规则所过滤,这样有时会出现L3层的iptables rules去过滤L2的帧的问题
net.bridge.bridge-nf-call-ip6tables = 1 #是否在ip6tables链中过滤IPv6包 

10.配置ipvs功能

在kubernetes中Service有两种代理模式,一种是基于iptables的,一种是基于ipvs,两者对比ipvs负载均衡算法更加的灵活,且带有健康检查的功能,如果想要使用ipvs模式,需要手动载入ipvs模块

#创建 /etc/modules-load.d/ipvs.conf 并加入以下内容: 
cat >/etc/modules-load.d/ipvs.conf <<EOF 
ip_vs 
ip_vs_lc 
ip_vs_wlc 
ip_vs_rr 
ip_vs_wrr 
ip_vs_lblc 
ip_vs_lblcr 
ip_vs_dh 
ip_vs_sh 
ip_vs_fo 
ip_vs_nq 
ip_vs_sed 
ip_vs_ftp 
ip_vs_sh 
nf_conntrack #内核小于4.18,把这行改成nf_conntrack_ipv4
ip_tables 
ip_set 
xt_set 
ipt_set 
ipt_rpfilter 
ipt_REJECT 
ipip 
EOF
#所有节点配置完内核后,重启服务器,保证重启后内核依旧加载
reboot -h now
#重启后查看ipvs模块加载情况:
lsmod | grep --color=auto -e ip_vs -e nf_conntrack
#重启后查看containerd相关模块加载情况:
lsmod | egrep 'br_netfilter | overlay'

或者

#推荐使用这个
cat >/etc/sysconfig/modules/ipvs.modules <<EOF 
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"
for kernel_module in ${ipvs_modules}; do
 /sbin/modinfo -F filename ${kernel_module} > /dev/null 2>&1
 if [ 0 -eq 0 ]; then
 /sbin/modprobe ${kernel_module}
 fi
done
EOF
#执行
bash /etc/sysconfig/modules/ipvs.modules
#查看
lsmod |grep ip_vs

11.安装docker
#安装docker需要的工具
yum install -y yum-utils
#配置镜像仓库
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#安装
yum -y install docker-ce-20.10.* docker-ce-cli-20.10.* containerd.io
#启动
systemctl enable docker && systemctl start docker
#修改 docker 配置(所有节点)
# kubernetes 官方推荐 docker 等使用 systemd 作为 cgroupdriver,否则 kubelet 启动不了
mkdir /etc/docker
cat <<EOF > /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": ["https://ud6340vz.mirror.aliyuncs.com"]
}
EOF
或者
tee /etc/docker/daemon.json <<-'EOF'
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": [
  	 "https://docker.rainbond.cc",
  	 "https://axvfsf7e.mirror.aliyuncs.com",
  	 "https://ud6340vz.mirror.aliyuncs.com"
  	]
}
EOF
# 重启生效
systemctl daemon-reload
systemctl restart docker

三、k8s部署

(一) kubeadm方式部署

1.配置k8s阿里源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

2.安装kubeadm、kubectl和kubelet
 2 0.300好0      20# 
 3指定版本安装
yum install -y kubelet-1.20.10 kubectl-1.20.10 kubeadm-1.20.10
#启动
systemctl enable kubelet && systemctl start kubelet
#组建讲解
Kubeadm: kubeadm 是一个工具,用来初始化 k8s 集群的
kubelet: 安装在集群所有节点上,用于启动 Pod 的
kubectl: 通过 kubectl 可以部署和管理应用,查看各种资源,创建、删除和更新各种组件0 

3.初始化主节点(仅在主节点跑)
#生成配置文件
kubeadm config print init-defaults > kubeadm-config.yaml
#修改配置文件
修改内容如下:
#第12行配置主节点IP地址
advertiseAddress: 192.168.47.10
#第16行修改
name: k8s-master
#第32行修改镜像下载地址
imageRepository: registry.aliyuncs.com/google_containers
#第34行修改版本为 
kubernetesVersion: v1.20.0
#第38行新增pod运行地址
podSubnet: 10.244.0.0/16
并在尾末加入下方配置:
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
#初始化安装
kubeadm init --config=kubeadm-config.yaml --upload-certs | tee kubeadm-init.log

出现以下代表初始化完成

1722218515521

根据日志提供执行以下操作为kebuctl提供

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

4.将工作节点添加到集群中
#将master生成后的token复制到工作节点执行,就能将工作节点添加到k8s集群中
#如果找不到这个加入命令可以使用进行kubeadm token create --print-join-command重新生成
kubeadm join 192.168.47.10:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:e21b9ed65344507f4f38eddeca3e3472fd825d92d1dc84a47136a4b6c5b04f9c
#删除一个工作节点
kubectl delete nodes k8s-node2

查看一下节点

kubectl get nodes

1722218828180

5.安装网络插件

可以看到节点status为notready状态,这个是因为需要安装网络插件。kubernetes网络插件有很多,比如flannel、calico等等,具体区别可以自行查询,本次我选用的是calico,网络插件需安装否则 node 是 NotReady 状态(主节点跑)

#下载部署 Calicos's
curl -O https://docs.tigera.io/archive/v3.18/manifests/calico.yaml
#修改文件vim calico
3672             - name: CALICO_IPV4POOL_CIDR
3673               value: "10.244.0.0/16"
添加
3688			 - name: IP_AUTODETECTION_METHOD
3689               value: "interface=ens32"
#应用文件
kubectl apply -f calico.yaml

查看calico部署进度

kubectl get pod -n kube-system
#如果有问题可以使用describe进行查看
kubectl describe pod calico-node-c7v7q -n kube-system

1722219749021

在查看一下节点状态

kubectl get nodes

1722219868120

6.检查k8s健康状态
kubectl get cs

1722220160698

解决方案

vim /etc/kubernetes/manifests/kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-scheduler
    tier: control-plane
  name: kube-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
   	#将这个port注释掉
    #- --port=0
vim /etc/kubernetes/manifests/kube-controller-manager.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-controller-manager
    tier: control-plane
  name: kube-controller-manager
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
    - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --bind-address=127.0.0.1
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --cluster-cidr=10.244.0.0/16
    - --cluster-name=kubernetes
    - --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
    - --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
    - --controllers=*,bootstrapsigner,tokencleaner
    - --kubeconfig=/etc/kubernetes/controller-manager.conf
    - --leader-elect=true
    #注释掉
    #- --port=0

再次检查

kubectl get cs

1722220507705

7.配置工作节点使用kubectl
#将master节点中/etc/kubernetes/admin.conf复制到对应机器节点上
scp /etc/kubernetes/admin.conf root@k8s-node1:/etc/kubernetes/
#在对应机器节点配置环境变量
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
#刷新下
source ~/.bash_profile

8.验证
#创建一个nginx进行测试,也可以写在yml中进行运行
kubectl create deployment nginx --image=nginx
#暴露一个端口,让外部可以进行访问
kubectl expose deployment nginx --port=80 --type=NodePort
#获取暴露的端口
[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        74m
nginx        NodePort    10.110.116.150   <none>        80:30249/TCP   15s
#使用ip进行访问
ip:30249
#查看当前运行的pod
[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6799fc88d8-sz4zw   1/1     Running   0          5m36s
#增加nginx副本
kubectl scale deploy --replicas=3 nginx
#查看
[root@k8s-master ~]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           9m54s
#减少nginx副本
kubectl scale deploy --replicas=1 nginx
#生成yml
kubectl get deploy nginx -o yaml
#删除
kubectl delete deploy nginx

查看pod并查看他们对应的节点

[root@k8s-master ~]# kubectl get pod -o wide

1722223387768

(二)二进制方式部署

1.部署Etcd集群

使⽤cfssl来⽣成⾃签证书,任何机器都⾏,证书这块⼉知道怎么⽣成、怎么⽤即可,暂且不⽤过多研究 (这个证书随便在那台机器⽣成都可以。哪⾥⽤将证书拷⻉到哪⾥就可以了。)

1.下载cfssl⼯具
#创建一个文件夹,用来下载工具
mkdir -p /opt/soft/cfssl && cd /opt/soft/cfssl
#下载cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
#下载cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
#下载cfssl-certinfo_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
#将下载的证书添加一个可执行权限
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
#移动证书
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

2.⽣成Etcd证书
#创建文件夹
mkdir -p /opt/soft/cert && cd /opt/soft/cert
#配置ca-csr.json证书请求文件
cat > ca-csr.json <<"EOF"
{
  "CN": "kubernetes",
  "key": {
      "algo": "rsa",
      "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "CQ",
      "L": "CQ",
      "O": "kubemsb",
      "OU": "CN"
    }
  ],
  "ca": {
          "expiry": "87600h"
  }
}
EOF
/*
说明
CN: COMMON NAME , 及名称,对于ssl证书,这里一般是网站域名, 而这里是签发的CA根证书,所以随便写都行。
Key:用于配置证书加密算法
Names: 用于配置企业信息,分别为: C:国家 ST:省。 L:所在地。 O:单位 OU:组织, 除此之外还有:E: 邮箱。 G: 其它姓名。 介绍: ,Phone:格式要求 + 国家区号 城市区号 电话号码,如: +86 732 88888888
,STREET: ,PostalCode等。
*/
#配置ca-config.json证书策略
cat > ca-config.json <<"EOF"
{
  "signing": {
      "default": {
          "expiry": "87600h"
        },
      "profiles": {
          "kubernetes": {
              "usages": [
                  "signing",
                  "key encipherment",
                  "server auth",
                  "client auth"
              ],
              "expiry": "87600h"
          }
      }
  }
}
EOF
说明
server auth 表示client可以对使用该ca对server提供的证书进行验证
client auth 表示server可以使用该ca对client提供的证书进行验证
#配置etcd-csr.json请求文件
cat > etcd-csr.json <<"EOF"
{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "192.168.134.10",
    "192.168.134.11",
    "192.168.134.12"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [{
    "C": "CN",
    "ST": "CQ",
    "L": "CQ",
    "O": "kubemsb",
    "OU": "CN"
  }]
}
EOF
#生成etcd证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson  -bare etcd
#查看刚刚生成的证书
[root@k8s-master cert]# ls *pem
ca-key.pem  ca.pem  etcd-key.pem  etcd.pem

3.安装Etcd
#切换目录
cd /opt/soft
#下载包
wget https://github.com/etcd-io/etcd/releases/download/v3.2.12/etcd-v3.2.12-linux-amd64.tar.gz
#etcd软件包安装
tar -xf etcd-v3.4.13-linux-amd64.tar.gz --strip-components=1 -C /usr/local/bin/ etcd-v3.4.13-linux-amd64/etcd*
#创建etcd配置文件,3个节点都要配置,并修改ETCD_NAME,ETCD_LISTEN_PEER_URLS,ETCD_LISTEN_CLIENT_URLS,ETCD_INITIAL_ADVERTISE_PEER_URLS,ETCD_ADVERTISE_CLIENT_URLS
mkdir /etc/etcd
cat >  /etc/etcd/etcd.conf <<"EOF"
#[Member]
ETCD_NAME="etcd1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.134.10:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.134.10:2379,http://127.0.0.1:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.134.10:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.134.10:2379"
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.134.10:2380,etcd2=https://192.168.134.11:2380,etcd3=https://192.168.134.12:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

/** 参数解释:
* ETCD_NAME 节点名称,每个节点名称不⼀样
* ETCD_DATA_DIR 存储数据⽬录(他是⼀个数据库,不是存在内存的,存在硬盘中的,所有和k8s
有关的信息都会存到etcd⾥⾯的)
* ETCD_LISTEN_PEER_URLS 集群通信监听地址
* ETCD_LISTEN_CLIENT_URLS 客户端访问监听地址
* ETCD_INITIAL_ADVERTISE_PEER_URLS 集群通告地址
* ETCD_ADVERTISE_CLIENT_URLS 客户端通告地址
* ETCD_INITIAL_CLUSTER 集群节点地址
* ETCD_INITIAL_CLUSTER_TOKEN 集群Token
* ETCD_INITIAL_CLUSTER_STATE 加⼊集群的当前状态,new是新集群,existing表示加⼊已有集群 */
#创建systemd管理etcd
cat > /usr/lib/systemd/system/etcd.service <<"EOF"
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/etc/etcd/etcd.conf
ExecStart=/usr/local/bin/etcd \
--cert-file=/etc/etcd/ssl/etcd.pem \
--key-file=/etc/etcd/ssl/etcd-key.pem \
--trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-cert-file=/etc/etcd/ssl/etcd.pem \
--peer-key-file=/etc/etcd/ssl/etcd-key.pem \
--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-client-cert-auth \
--client-cert-auth
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
#创建启动etcd需要的目录
mkdir -p /etc/etcd/ssl
mkdir -p /var/lib/etcd/default.etcd
#将证书复制到/etc/etcd/ssl
cp /opt/soft/cert/ca*.pem /etc/etcd/ssl
cp /opt/soft/cert/etcd*.pem /etc/etcd/ssl
#全部启动并设置开启启动,启动时一定要同时启动,否则会报错
systemctl daemon-reload && systemctl start etcd && systemctl enable etcd
#验证是否安装成功
ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.134.10:2379,https://192.168.134.11:2379,https://192.168.134.12:2379 endpoint health

2.部署api-server

在master节点部署api-server,master节点操作--给api-server创建的证书。别的服务访问api-server的时候需要通过证书认证

#下载软件包
wget https://dl.k8s.io/v1.20.10/kubernetes-server-linux-amd64.tar.gz
#解压包到/usr/local/bin下
tar -xf kubernetes-server-linux-amd64.tar.gz --strip-components=3 -C /usr/local/bin kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy}
#将k8s程序传到node
scp /usr/local/bin/kube{let,-proxy} root@k8s-node1:/usr/local/bin
scp /usr/local/bin/kube{let,-proxy} root@k8s-node2:/usr/local/bin
#在master节点创建以下文件夹
mkdir -p /etc/kubernetes/        
mkdir -p /etc/kubernetes/ssl     
mkdir -p /var/log/kubernetes 

1.生成apiserver证书
#创建目录用来生成证书
cd /opt/soft/cert
#创建apiserver证书请求文件
cat > kube-apiserver-csr.json << "EOF"
{
"CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "192.168.134.10",
    "192.168.134.11",
    "192.168.134.12",
    "10.96.0.1",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "CQ",
      "L": "CQ",
      "O": "kubemsb",
      "OU": "CN"
    }
  ]
}
EOF
#说明:
如果 hosts 字段不为空则需要指定授权使用该证书的 IP(含VIP) 或域名列表。由于该证书被 集群使用,需要将节点的IP都填上,为了方便后期扩容可以多写几个预留的IP。
同时还需要填写 service 网络的首个IP(一般是 kube-apiserver 指定的 service-cluster-ip-range 网段的第一个IP,如 10.96.0.1)。
#生成apiserver证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-apiserver-csr.json | cfssljson -bare kube-apiserver
#生成token文件
cat > token.csv << EOF
$(head -c 16 /dev/urandom | od -An -t x | tr -d ' '),kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
#说明:
创建TLS机制所需TOKEN
TLS Bootstraping:Master apiserver启用TLS认证后,Node节点kubelet和kube-proxy与kube-apiserver进行通信,必须使用CA签发的有效证书才可以,当Node节点很多时,这种客户端证书颁发需要大量工作,同样也会增加集群扩展复杂度。为了简化流程,Kubernetes引入了TLS bootstraping机制来自动颁发客户端证书,kubelet会以一个低权限用户自动向apiserver申请证书,kubelet的证书由apiserver动态签署。所以强烈建议在Node上使用这种方式,目前主要用于kubelet,kube-proxy还是由我们统一颁发一个证书。
#将证书复制到/etc/kubernetes/ssl
cp ca-key.pem ca.pem token.csv kube-apiserver-key.pem kube-apiserver.pem /etc/kubernetes/ssl/

2.创建apiserver服务配置文件
cat > /etc/kubernetes/kube-apiserver.conf << "EOF"
KUBE_APISERVER_OPTS="--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --anonymous-auth=false \
  --bind-address=192.168.134.10 \
  --secure-port=6443 \
  --advertise-address=192.168.134.10 \
  --insecure-port=0 \
  --authorization-mode=Node,RBAC \
  --runtime-config=api/all=true \
  --enable-bootstrap-token-auth \
  --service-cluster-ip-range=10.96.0.0/16 \
  --token-auth-file=/etc/kubernetes/ssl/token.csv \
  --service-node-port-range=30000-32767 \
  --tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem  \
  --tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem \
  --client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem \
  --kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem \
  --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
  --service-account-signing-key-file=/etc/kubernetes/ssl/ca-key.pem  \
  --service-account-issuer=api \
  --etcd-cafile=/etc/etcd/ssl/ca.pem \
  --etcd-certfile=/etc/etcd/ssl/etcd.pem \
  --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \
  --etcd-servers=https://192.168.134.10:2379,https://192.168.134.11:2379,https://192.168.134.12:2379 \
  --enable-swagger-ui=true \
  --allow-privileged=true \
  --apiserver-count=3 \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/kube-apiserver-audit.log \
  --event-ttl=1h \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=4"
EOF
#创建systemd管理apiserver
cat > /usr/lib/systemd/system/kube-apiserver.service << "EOF"
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=etcd.service
Wants=etcd.service

[Service]
EnvironmentFile=-/etc/kubernetes/kube-apiserver.conf
ExecStart=/usr/local/bin/kube-apiserver $KUBE_APISERVER_OPTS
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
#启动apiserver服务
systemctl daemon-reload
systemctl enable --now kube-apiserver
systemctl status kube-apiserver
# 测试
curl --insecure https://192.168.134.10:6443/
curl --insecure https://192.168.134.11:6443/
curl --insecure https://192.168.134.12:6443/

3.部署kubectl
1.生成kubectl证书
cd /opt/soft/cert
#创建kubectl证书请求文件
cat > admin-csr.json << "EOF"
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "CQ",
      "L": "CQ",
      "O": "system:masters",             
      "OU": "system"
    }
  ]
}
EOF
#说明:
后续 kube-apiserver 使用 RBAC 对客户端(如 kubelet、kube-proxy、Pod)请求进行授权;
kube-apiserver 预定义了一些 RBAC 使用的 RoleBindings,如 cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 的所有 API的权限;
O指定该证书的 Group 为 system:masters,kubelet 使用该证书访问 kube-apiserver 时 ,由于证书被 CA 签名,所以认证通过,同时由于证书用户组为经过预授权的 system:masters,所以被授予访问所有 API 的权限;
注:
这个admin 证书,是将来生成管理员用的kubeconfig 配置文件用的,现在我们一般建议使用RBAC 来对kubernetes 进行角色权限控制, kubernetes 将证书中的CN 字段 作为User, O 字段作为 Group;
"O": "system:masters", 必须是system:masters,否则后面kubectl create clusterrolebinding报错。
#生成证书文件
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
#复制文件到指定目录
cp admin*.pem /etc/kubernetes/ssl/

2.生成kubeconfig配置文件
#kube.config 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.134.10:6443 --kubeconfig=kube.config

kubectl config set-credentials admin --client-certificate=admin.pem --client-key=admin-key.pem --embed-certs=true --kubeconfig=kube.config

kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=kube.config

kubectl config use-context kubernetes --kubeconfig=kube.config
#准备kubectl配置文件并进行角色绑定
mkdir ~/.kube
cp kube.config ~/.kube/config
kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes --kubeconfig=/root/.kube/config
#查看集群状态
export KUBECONFIG=$HOME/.kube/config
#查看集群信息
kubectl cluster-info
#查看集群组件状态
kubectl get componentstatuses
#查看命名空间中资源对象
kubectl get all --all-namespaces

4.部署kube-controller-manager
1.生成kube-controller-manager证书
#切换目录
cd /opt/soft/cert
#创建证书文件
cat > kube-controller-manager-csr.json << "EOF"
{
    "CN": "system:kube-controller-manager",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
      "127.0.0.1",
      "192.168.134.10"
    ],
    "names": [
      {
        "C": "CN",
        "ST": "CQ",
        "L": "CQ",
        "O": "system:kube-controller-manager",
        "OU": "system"
      }
    ]
}
EOF
说明:
hosts 列表包含所有 kube-controller-manager 节点 IP;
CN 为 system:kube-controller-manager;
O 为 system:kube-controller-manager,kubernetes 内置的 ClusterRoleBindings system:kube-controller-manager 赋予 kube-controller-manager 工作所需的权限
#创建kube-controller-manager证书文件
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
#创建kube-controller-manager的kube-controller-manager.kubeconfig
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.134.10:6443 --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-credentials system:kube-controller-manager --client-certificate=kube-controller-manager.pem --client-key=kube-controller-manager-key.pem --embed-certs=true --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-context system:kube-controller-manager --cluster=kubernetes --user=system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig

kubectl config use-context system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig
#复制到配置文件
cp kube-controller-manager*.pem /etc/kubernetes/ssl/
cp kube-controller-manager.kubeconfig /etc/kubernetes/

2.创建kube-controller-manager配置文件和服务
cat > /etc/kubernetes/kube-controller-manager.conf << "EOF"
KUBE_CONTROLLER_MANAGER_OPTS="--secure-port=10257 \
  --bind-address=127.0.0.1 \
  --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \
  --service-cluster-ip-range=10.96.0.0/16 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \
  --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
  --allocate-node-cidrs=true \
  --cluster-cidr=10.244.0.0/16 \
  --experimental-cluster-signing-duration=87600h \
  --root-ca-file=/etc/kubernetes/ssl/ca.pem \
  --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \
  --leader-elect=true \
  --feature-gates=RotateKubeletServerCertificate=true \
  --controllers=*,bootstrapsigner,tokencleaner \
  --horizontal-pod-autoscaler-sync-period=10s \
  --tls-cert-file=/etc/kubernetes/ssl/kube-controller-manager.pem \
  --tls-private-key-file=/etc/kubernetes/ssl/kube-controller-manager-key.pem \
  --use-service-account-credentials=true \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2"
EOF
#创建systemd管理kube-controller-manager
cat > /usr/lib/systemd/system/kube-controller-manager.service << "EOF"
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/etc/kubernetes/kube-controller-manager.conf
ExecStart=/usr/local/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
# 启动服务
systemctl daemon-reload 
systemctl enable --now kube-controller-manager
systemctl status kube-controller-manager

5.部署kube-scheduler
1.生成kube-scheduler证书
#切换目录
cd /opt/soft/cert
#创建kube-scheduler-csr.json文件
cat > kube-scheduler-csr.json << "EOF"
{
    "CN": "system:kube-scheduler",
    "hosts": [
      "127.0.0.1",
      "192.168.134.10"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
      {
        "C": "CN",
        "ST": "CQ",
        "L": "CQ",
        "O": "system:kube-scheduler",
        "OU": "system"
      }
    ]
}
EOF
#生成kube-scheduler证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
#创建ube-scheduler的kubeconfig
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.134.10:6443 --kubeconfig=kube-scheduler.kubeconfig

kubectl config set-credentials system:kube-scheduler --client-certificate=kube-scheduler.pem --client-key=kube-scheduler-key.pem --embed-certs=true --kubeconfig=kube-scheduler.kubeconfig

kubectl config set-context system:kube-scheduler --cluster=kubernetes --user=system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig

kubectl config use-context system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig
#复制证书到证书存放目录
cp kube-scheduler*.pem /etc/kubernetes/ssl/
#复制配置文件到/etc/kubernetes/
cp kube-scheduler.kubeconfig /etc/kubernetes/

2.创建scheduler配置文件和服务
#创建服务配置文件
cat > /etc/kubernetes/kube-scheduler.conf << "EOF"
KUBE_SCHEDULER_OPTS="--address=127.0.0.1 \
--kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
--leader-elect=true \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2"
EOF
#创建服务启动配置文件
cat > /usr/lib/systemd/system/kube-scheduler.service << "EOF"
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/etc/kubernetes/kube-scheduler.conf
ExecStart=/usr/local/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
#启动服务
systemctl daemon-reload
systemctl enable --now kube-scheduler
systemctl status kube-scheduler

6.部署kubelet
#创建kubelet-bootstrap.kubeconfig
BOOTSTRAP_TOKEN=$(awk -F "," '{print $1}' /etc/kubernetes/ssl/token.csv)

kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.134.10:6443 --kubeconfig=kubelet-bootstrap.kubeconfig

kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=kubelet-bootstrap.kubeconfig

kubectl config set-context default --cluster=kubernetes --user=kubelet-bootstrap --kubeconfig=kubelet-bootstrap.kubeconfig

kubectl config use-context default --kubeconfig=kubelet-bootstrap.kubeconfig

kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=kubelet-bootstrap

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap --kubeconfig=kubelet-bootstrap.kubeconfig

kubectl describe clusterrolebinding cluster-system-anonymous

kubectl describe clusterrolebinding kubelet-bootstrap
#复制到配置目录
cp kubelet-bootstrap.kubeconfig /etc/kubernetes/
# 创建kubelet配置文件
cat > /etc/kubernetes/kubelet.json << "EOF"
{
  "kind": "KubeletConfiguration",
  "apiVersion": "kubelet.config.k8s.io/v1beta1",
  "authentication": {
    "x509": {
      "clientCAFile": "/etc/kubernetes/ssl/ca.pem"
    },
    "webhook": {
      "enabled": true,
      "cacheTTL": "2m0s"
    },
    "anonymous": {
      "enabled": false
    }
  },
  "authorization": {
    "mode": "Webhook",
    "webhook": {
      "cacheAuthorizedTTL": "5m0s",
      "cacheUnauthorizedTTL": "30s"
    }
  },
  "address": "192.168.134.10",
  "port": 10250,
  "readOnlyPort": 10255,
  "cgroupDriver": "systemd",                    
  "hairpinMode": "promiscuous-bridge",
  "serializeImagePulls": false,
  "clusterDomain": "cluster.local.",
  "clusterDNS": ["10.96.0.2"]
}
EOF
#创建kubelet服务启动管理文件
cat > /usr/lib/systemd/system/kubelet.service << "EOF"
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/local/bin/kubelet \
  --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \
  --cert-dir=/etc/kubernetes/ssl \
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
  --config=/etc/kubernetes/kubelet.json \
  --container-runtime-endpoint=unix:///run/containerd/containerd.sock \
  --rotate-certificates \
  --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.2 \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

#创建目录及启动服务
mkdir -p /var/lib/kubelet
mkdir -p /var/log/kubernetes
systemctl daemon-reload
systemctl enable --now kubelet
systemctl status kubelet
#查看节点
[root@k8s-master ~]# kubectl get nodes
NAME         STATUS   ROLES    AGE   VERSION
k8s-master   Ready    <none>   73s   v1.20.10

7.部署kube-proxy
#切换目录
cd /opt/soft/cert/
# 创建kube-proxy证书请求文件
cat > kube-proxy-csr.json << "EOF"
{
  "CN": "system:kube-proxy",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "CQ",
      "L": "CQ",
      "O": "kubemsb",
      "OU": "CN"
    }
  ]
}
EOF
#生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
#创建kubeconfig文件
kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.134.10:6443 --kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy --client-certificate=kube-proxy.pem --client-key=kube-proxy-key.pem --embed-certs=true --kubeconfig=kube-proxy.kubeconfig

kubectl config set-context default --cluster=kubernetes --user=kube-proxy --kubeconfig=kube-proxy.kubeconfig

kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
#创建服务配置文件
cat > kube-proxy.yaml << "EOF"
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 192.168.134.10
clientConnection:
  kubeconfig: /etc/kubernetes/kube-proxy.kubeconfig
clusterCIDR: 10.244.0.0/16
healthzBindAddress: 192.168.134.10:10256
kind: KubeProxyConfiguration
metricsBindAddress: 192.168.134.10:10249
mode: "ipvs"
EOF
#创建服务启动管理文件
cat >  /usr/lib/systemd/system/kube-proxy.service << "EOF"
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/local/bin/kube-proxy \
  --config=/etc/kubernetes/kube-proxy.yaml \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
#复制到配置文件目录
cp kube-proxy*.pem /etc/kubernetes/ssl/
cp kube-proxy.kubeconfig kube-proxy.yaml /etc/kubernetes/
# 服务启动
mkdir -p /var/lib/kube-proxy
systemctl daemon-reload
systemctl enable --now kube-proxy
systemctl status kube-proxy

8.工作节点安装
1.工作节点部署kubelet
#在master节点切换目录
cd /opt/soft/cert
#在工作节点创建目录
mkdir /etc/kubernetes/
mkdir /etc/kubernetes/ssl
#同步至集群节点
for i in k8s-node1 k8s-node2;do scp /etc/kubernetes/kubelet-bootstrap.kubeconfig /etc/kubernetes/kubelet.json $i:/etc/kubernetes/;done

for i in  k8s-node1 k8s-node2;do scp ca.pem $i:/etc/kubernetes/ssl/;done

for i in k8s-node1 k8s-node2;do scp /usr/lib/systemd/system/kubelet.service $i:/usr/lib/systemd/system/;done
#复制到工作节点后需要修改一下工作节点中ip
sed -ri 's/"address": "192.168.134.10"/"address": "192.168.134.11"/g' /etc/kubernetes/kubelet.json
sed -ri 's/"address": "192.168.134.10"/"address": "192.168.134.12"/g' /etc/kubernetes/kubelet.json
#在工作节点执行创建目录及启动服务
mkdir -p /var/lib/kubelet
mkdir -p /var/log/kubernetes
systemctl daemon-reload
systemctl enable --now kubelet
systemctl status kubelet
#查看节点
[root@k8s-master ~]# kubectl get nodes
NAME         STATUS   ROLES    AGE     VERSION
k8s-master   Ready    <none>   15m     v1.20.10
k8s-node1    Ready    <none>   2m53s   v1.20.10
k8s-node2    Ready    <none>   2m38s   v1.20.10

2.工作节点部署kube-proxy
#同步文件到集群工作节点主机,修改kube-proxy.yaml中IP地址为当前主机IP
for i in k8s-node1 k8s-node2;do scp /etc/kubernetes/kube-proxy.kubeconfig /etc/kubernetes/kube-proxy.yaml $i:/etc/kubernetes/;done
for i in k8s-node1 k8s-node2;do scp  /usr/lib/systemd/system/kube-proxy.service $i:/usr/lib/systemd/system/;done
# 服务启动
mkdir -p /var/lib/kube-proxy
systemctl daemon-reload
systemctl enable --now kube-proxy
systemctl status kube-proxy

9.网络组件部署 Calico
#下载部署 Calico
wget https://docs.projectcalico.org/v3.19/manifests/calico.yaml
#修改文件vim calico
3683             - name: CALICO_IPV4POOL_CIDR
3684               value: "10.244.0.0/16"
#应用文件
kubectl apply -f calico.yaml

四、k8s资源管理

1.k8s服务类型
  • 无状态服务
    • 代表应用:nginx,Apache
    • 优点:无依赖关系,可以高效扩容,迁移
    • 缺点:不能存储数据
  • 有状态服务
    • 代表应用:mysql,redis
    • 优点:可以独立存储数据
    • 缺点:需要数据同步,备份,水平扩容复杂
2.K8s资源类型介绍

资源分类:

  • 元数据型
    • 扩缩容,模版定制,资源分配
  • 集群级
    • 命名空间,节点资源,认证,角色
  • 命名空间级
    • 工作负载,配置存储,服务发现等。
资源名称缩写资源作用
nodesno查看k8s中的所有节点
namespacesns名称空间,隔离pod
podspo,pod装载容器(容器组)
replicationcontrollersrc控制器(无状态服务,适用nginx等,已淘汰)
replicasetsrs控制器(无状态服务,适用nginx等,已淘汰)
deploymentsdeploy控制器(无状态服务,适用nginx等,rc,rs有的都有,推荐)
daemonsetsds控制器(守护进程,适用于监控,日子收集)
jobs控制器(任务)
cronjobscj控制器(定时)
horizontalpodautoscalershpa控制pod资源
statefulsetssts控制器(有状态服务,适用mysql等)
servicessvc4层负载均衡,集群内部网络通信
ingressing7层负载均衡,集群外部网络通信(就是nginx)
volumeattachments存储资源(类似挂载)
persistentvolumespv存储资源
persistentvolumeclaimspvc存储资源
configmapscm配置资源(存放配置信息)
secrets加密配置资源
serviceaccountsa服务账户
3.kubectl命令介绍

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

kubectl常用命令如下

命令作用
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、
servicename:指定资源名称,名称区分大小写
flags:指定额外的可选参数,例如:-o  wide

4.kubectl常用命令

查看pod

#查看所有pod
[root@k8s-master ~]# kubectl get pods --all-namespaces
#查看指定的pod(根据pod名字查找)
kubectl get pod pod名称
#查看指定pod,通过额外参数显示pod详细信息,包括pod的IP地址,pod运行的节点等
kubectl get pod pod名称 -o wide
#查看指定pod,通过额外参数显示pod信息,以json格式显示
kubectl get pod pod名称 -o json
#查看指定pod,通过额外参数显示pod信息,以yaml格式显示
kubectl get pod pod名称 -o yaml
#显示指定pod资源内部信息
kubectl describe pod pod名称

1722223832533

查看所有节点

[root@k8s-master ~]# kubectl get nodes

1722223884942

显示当前Server和Client版本信息

kubectl version

显示集群信息

kubectl cluster-info

五、Namespace名称空间

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

1.查看名称空间
[root@k8s-master ~]# kubectl get ns/namespace
NAME              STATUS   AGE
default           Active   32h	#不指定时默然创建到此空间
kube-node-lease   Active   32h	#集群节点之间的心跳维护
kube-public       Active   32h	#该名称空间下的资源可以被所有人访问
kube-system       Active   32h	#系统创建的资源

1722221497866

2.查看指定ns的信息
[root@k8s-master ~]# kubectl get pod -n kube-system

1722221538845

3.创建一个名称空间
kubectl create namespace test
或者
kubectl create ns test 

4.删除名称空间
kubectl delete namespace test
或者
kubectl delete ns test

5.yaml创建

#vim test_namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test
# 创建命令
kubectl create/apply -f test_namespace.yaml

六、资源管理语言yaml

k8s中几乎所有的资源都可以通YAML编排来创建。

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

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

对象键值对类型

xxx:
  key: value

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

- xxx:
  key: value

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

xxx:
  key: v
  - key: v
  key: v

3.K8s资源对象描述

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

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

4.YAML文件创建资源

使用yaml创建一个简单的pod

#vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0

七、pod与pod控制器

1.Pod概念介绍

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

Pod是容器组,一个Pod中可以存在一个或多个容器,这些容器共享Pod中的存储、网络等资源,所以我们可以把Pod看做一台物理服务器一样(Pod不是进程,而是容器运行的环境),其中包含一个或多个应用容器,这些容器中运行着用户应用程序。

pod的创建方式分为两类:

**静态Pod:**也称之为无控制器管理的自主式pod,直接由特定节点上的kubelet守护进程管理,不需要API服务器看到它们,对于静态Pod而言,kubelet直接监控每个Pod,这种pod删除后就没有了,也不会重建。

示例

# vim nginx-web.yaml
apiVersion: v1  #api文档版本
kind: Pod       #资源对象类型,如deployment
metadata:       #描述pod数据
  name: nginx-web       #名称
  labels:       #定义pod标签
  namespace: 'default' #指定名称空间
spec:   #按照这里面的描述进行创建
  containers:   #对于pod中容器的描述
  - name: nginx-web     #容器名称
    image: nginx:1.18.0 #具体镜像
    imagePullPolicy: IfNotPresent #镜像拉去策略,如果本地有就是用本地的,没有拉去远程的
    livenessProbe: #存活性探针配置
      httpGet: #探测方式,http
        path: /index.html #http请求路径
        port: 80 #请求端口
      failureThreshold: 3 #失败多少次才是真正失败
      periodSeconds: 10 #间隔检测时间
      successThreshold: 1 #多少次检测成功算成功
      timeoutSeconds: 5 #请求的超时时间
    workingDir: /usr/share/nginx/html   #指定启动后进入的工作目录
    ports:      #端口暴露
    - name: nginx-web #名称
      containerPort: 80 #容器内要暴露什么端口
      protocol: TCP #基于容器配置端口的协议
    env:      #环境变量配置
    - name: JVM_OPTS #环境变量名称
      value: '-Xms128m -Xmx128m' #值
    resources:
      requests: #最少需要多少资源
        cpu: 100m #限制CPU最少使用量
        memory: 128Mi #内存最少使用128M
      limits: #最多使用多少资源
        cpu: 200m #限制CPU最多使用量
        memory: 256Mi #内存最多使用256M
  restartPolicy: Always #重启策略

创建pod

#执行创建
kubectl create -f nginx-web.yaml
#查看pod
kubectl get pod
#删除pod
kubectl delete pod nginx-web

1722228518184

**控制器管理的pod:**控制器可以控制pod的副本数,扩容与缩容、版本更新、版本回滚等。

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

常见pod控制器种类:

ReplicationController:比较原始的pod控制器,目前已经被废弃,由ReplicaSet代替
ReplicaSet:保证指定数量的pod运行,并支持pod数量变更,镜像版本变更
Deployment:通过控制ReplicaSet来控制pod,包含ReplicaSet所有功能,还支持滚动升级,版本回退
Horizontal Pod Autoscaler:可以根据集群负载自动调整pod数量,实现pod扩容缩
DaemonSet:节点级别控制器,确保全部每一个节点上运行一个Pod的副本,当有Node加入集群时,也会为他们新增一个Pod,当有Node从集群移除时,这些Pod也会被回收,删除DaemonSet将会删除它创建的所有Pod
Job:运行一次性任务的Pod,它创建的pod只要完成就立即退出(健康检查,数据备份)

示例:

#vim deploy_nginx.yml
apiVersion: apps/v1 #查看版本[root@k8s-master ~]# kubectl explain deploy.apiVersion
kind: Deployment #资源类型Deployment
metadata: #元信息
  labels: #标签
    app: deploy-nginx #具体的标签名
  name: deploy-nginx #Deployment的名称
  namespace: 'default' #名称空间
spec: #Deployment期望信息
  replicas: 2 #指定副本数量
  revisionHistoryLimit: 10 #滚动更新后保留的历史版本数
  selector: #选择器,找到相应的RS
    matchLabels: #按照标签匹配
      app: deploy-nginx #匹配的标签值
  strategy: #更新策略
    rollingUpdate: #滚动更新配置
      maxSurge: 25% #进行滚动更新时,更新个数最多可以超过数
      maxUnavailable: 25% #进行滚动更新时最大不可用比例
    type: RollingUpdate #采用滚动更新
  template:	#模板
    metadata: #pod的元数据
      labels: #pod的标签
        app: deploy-nginx #pod的标签值
    spec: #pod的期望信息
      containers: #pod的容器
      - name: nginx #容器的名称
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent #镜像拉去策略
      restartPolicy: Always #重启策略

创建

kubectl create -f deploy_nginx.yml
#获取
[root@k8s-master /opt/k8s]# kubectl get deploy

1722237431725

2.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对象到容器内部

3.Pod控制器ReplicaSet

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

1.ReplicaSet应用案例
#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.20.0

2.ReplicaSet扩缩容

通过RS控制器实现Pod数量的扩缩容功能

#通过edit(配置文件形式)可直接在线修改资源的配置
kubectl edit rs rs-nginx -n test
spec:
replicas: 6 #直接根据需求修改pod的副本数量即可
#查看pod信息
kubectl get pod -n test

3.ReplicaSet版本变更

通过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

5.删除RS方式
命令删除方式
# kubectl delete rs rs-nginx -n test
查看rs信息
# kubectl get rs -n test
配置文件删除方式
# kubectl delete -f rs-nginx.yml

4.Pod控制器Deployment

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

Deployment功能如下:

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

1.Deployment应用案列
# 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.18.0

创建deploy

#创建deploy
kubectl create -f deploy_nginx.yml
#查看deploy详细信息
kubectl get deploy -n test
kubectl get deploy -n test -o wide

5.Pod 镜像拉取策略

imagePullPolicy用于设置镜像拉取策略,k8s支持三种拉取策略,可通过下边命令查看:

[root@k8s-master ~]#  kubectl explain pod.spec.containers.imagePullPolicy

  • Always
    • 总是从远程仓库拉取镜像
  • IfNotPresent
    • 本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
  • Never
    • 只使用本地镜像,从不去远程仓库拉取,本地如果没有就报错
1.Pod 镜像拉取策略 Never

案例:创建pod,并指定镜像拉取策略为Never,只使用本地镜像,从不去远程仓库拉取,本地如果没有就报错。

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0 #指定一个本地不存的镜像版本
        imagePullPolicy: Never #设置镜像拉取策略
#创建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

2.Pod 镜像拉取策略 IfNotPresent

案例:创建pod,并指定镜像拉取策略为IfNotPresent,本地有则使用本地镜像,本地没有则从远程仓库拉取镜像

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0 #指定一个本地不存的镜像版本
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
#创建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

6.Pod端口设置

ports属性用于配置容器需要暴露的端口列表

#通过下边命令可以获取ports可以使用的子属性
[root@k8s-master ~]# kubectl explain pod.spec.containers.ports

  • containerPort
    • 容器要监听的端口(不定义,采用默认端口)
  • name
    • 端口名称,如果指定,必须保证名称在该pod中是唯一的
  • protocol
    • 端口协议,必须是TCP、UDP或SCTP,默认为TCP

案例:创建Pod并指定容器暴露80端口

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent
        ports: #定义容器端口
        - containerPort: #80 端口(必须为数组类型)
          name: nginx-web #指定端口名称
          protocol: TCP #端口协议
创建pod
# kubectl create -f deploy_nginx.yml
查看pod信息
# kubectl get pod -n test
# curl ip:80
删除deploy
# kubectl delete -f deploy_nginx.yml

7.Pod资源配额

resources属性用于限制Pod中的容器对系统的资源的使用量(资源配额),避免容器出现问题大量吞噬系统资源,k8s目前提供了对内存和CPU的资源限制 当我们对Pod中的容器配置资源限额以后,如果容器超出资源使用量,k8s则会认位该容器出现故障,则重新启动该容器

resources属性提供了两个子属性用于资源限制,可通过下边命令查看:

kubectl explain pod.spec.containers.resources

  • limits
    • 资源上限:限制容器运行时最大的资源使用量,当容器超出该使用量时,容器会被终止,并进行重启
  • requests
    • 资源下限:用于限制容器需要的最小资源,如果环境资源不够,容器将无法启动

案例:创建pod并设置容器资源的上下限

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:
          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
curl ip:80
#删除deploy
kubectl delete -f deploy_nginx.yml

8.Pod多容器创建方式

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

# vim deploy_nginx_tomcat.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx-tomcat
  namespace: test
spec:
  replicas: 1
  selector: #标签选择器(基于选择器匹配Pod)
    matchLabels: #标签类型
      app: deploy-nginx-tomcat #匹配pod的标签(表示deploy管理带有此标签的Pod)
  template: #pod的配置模板
    metadata:
      labels:
        app: deploy-nginx-tomcat #pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义容器端口
        - 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
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义容器端口
        - 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_tomcat.yml
#查看pod信息
kubectl get pod -n test
curl ip:80
#删除deploy
kubectl delete -f deploy_nginx_tomcat.yml

9.Pod环境变量

evn属性是用于设置容器环境变量的列表,环境变量的定义要根据容器具体需求定义。

可通过下方命令获取env文档帮助:

[root@k8s-master ~]# kubectl explain pod.spec.containers.env

  • name
    • 定义环境变量名称
  • value
    • 定义变量值

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

# vim env_mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: env-mysql
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: env-mysql
  template:
    metadata:
      labels:
        app: env-mysql
    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 env_mysql.yml
#查看Pod信息
kubectl get pod -n test
#查看Pod详细描述
kubectl describe pod -n test

10.Pod 容器进入方式
格式:kubectl exec -n 命名空间 -it pod名称 -c 容器名称 -- /bin/bash
-c 容器名为可选项,如果是1个pod中1个容器,则不用指定;
如果是1个pod中多个容器,不指定默认为第1个。

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

kubectl exec -n test -it env-mysql-5f5548cd6c-45n47 -c mysql -- /bin/bash

Pod容器执行命令方式

kubectl exec deploy-nginx-698c84cc44-82mj9  -n test -c nginx -- ls /etc/nginx

11.Pod容器探针

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

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

[root@k8s-master ~]# kubectl explain pod.spec.containers

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

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

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

以livenessProbe存活性探针的两种常用的探测方式:

1.Pod 容器探测 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:
      tolerations: #添加容忍
      - key: "k8s-node1" #污点的key(必须引起来)
        effect: NoSchedule #污点类型
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义容器端口
        - containerPort: #80 端口(必须为数组类型)
          protocol: TCP #端口协议
        livenessProbe: #存活性探针
          exec: #命令探测方式
            command: [/bin/ls,/etc/hello.txt] #探测一个不存在的文件
        failureThreshold: 3 #失败多少次才是真正失败
        periodSeconds: 10 #间隔检测时间
        successThreshold: 1 #多少次检测成功算成功
        timeoutSeconds: 5 #请求的超时时间
#创建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

2.Pod 容器探测 tcpSocket

方式二: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:
      tolerations: #添加容忍
      - key: "k8s-node1" #污点的key(必须引起来)
        effect: NoSchedule #污点类型
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent #设置镜像拉取策略
        ports: #定义容器端口
        - containerPort: #80 端口(必须为数组类型)
          protocol: TCP #端口协议
        livenessProbe: #存活性探针
          tcpSocket: #端口探测方式
            port: 8080 #探测一个不存在的端口
        failureThreshold: 3 #失败多少次才是真正失败
        periodSeconds: 10 #间隔检测时间
        successThreshold: 1 #多少次检测成功算成功
        timeoutSeconds: 5 #请求的超时时间
#创建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

12.Pod容器重启策略

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

[root@k8s-master ~]# kubectl explain pod.spec.restartPolicy

  • Always:
    • 容器失效时,自动重启该容器,默认策略
  • OnFailure:
    • 容器终止运行且退出码不为0时重启(异常终止)
  • Never:
    • 无论容器状态如何,都不重启该容器

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

13.Pod数量扩缩容

方法一:通过Deploy对pod数量进行扩缩容

# kubectl edit deploy deploy-nginx -n test
...
replicas: 2 #修改pod数量

方法二:通过scale进行扩缩容

kubectl scale --replicas=3 deploy deploy-nginx -n test

14.Pod版本更新策略

Deploy支持两种镜像更新的策略:通过strategy属性进行配置

[root@k8s-master ~]# kubectl explain deploy.spec.strategy

  • Recreate:
    • 重建更新策略,一次性将所有旧版本pod全部重建成新版本pod
  • RollingUpdat:
    • 滚动更新策略(默认策略),先删除一部分旧版本pod,在更新成新版本pod
1.Pod版本更新Recreate

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

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  strategy: #Pod更新策略
    type: Recreate #重建更新
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:
          protocol: TCP
#创建pod
kubectl create -f deploy_nginx.yml
#查看pod信息
kubectl get pod -n test
#删除deploy
kubectl delete -f deploy_nginx.yml

2.Pod版本更新RollingUpdat

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

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  strategy: #Pod更新策略
    type: RollingUpdat #滚动更新策略
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:
          protocol: TCP
#创建pod
kubectl create -f deploy_nginx.yml
#查看pod信息
kubectl get pod -n test
#删除deploy
kubectl delete -f deploy_nginx.yml

15.Pod版本回退

Deploy支持版本升级过程中的暂停、继续、回退等功能,具体功能如下:

  • status
    • 显示当前升级状态
  • history
    • 显示升级历史记录
  • pause
    • 暂停版本升级过程
  • resume
    • 继续已经暂停的版本升级过程
  • restart
    • 重启版本升级过程
  • undo
    • 回滚到上一级版本(可以通过--to-revision回滚到指定版本)

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

查看升级历史记录

kubectl rollout history deploy deploy-nginx -n test

1722240093018

查看具体版本详细信息:--revision=版本编号

kubectl rollout history deploy deploy-nginx --revision=2 -n test

1722240162185

查看版本

#查看当前所有版本(通过rs可以查看)
kubectl get rs -o wide -n test
#查看当前使用版本(查看deploy)
kubectl get deploy -o wide -n test

1722240270509

版本回退:通过--to-revision=1,可直接回滚到1版本,如果省略这个选项,就是回退到上个版本

kubectl rollout undo deploy deploy-nginx --to-revision=1 -n test
#查看当前使用的版本
kubectl get deploy -o wide -n test
#查看升级历史记录
kubectl rollout history deploy deploy-nginx -n test

1722240336330

16.Pod控制器StatefulSet

StatefulSet适用于有状态应用的部署,如mysql等。会依赖于本地文件。

案列:

vim statefulset-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-service
  name: nginx-service
  namespace: test
spec:
  ports:
  - port: 80
    name: nginx-service
  clusterIP: None
  selector:
    app: nginx-service
---
apiVersion: apps/v1
kind: StatefulSet #StatefulSet类型的资源
metadata:
  labels:
    app: statefulset-nginx
  name: statefulset-nginx #StatefulSet名称
  namespace: test
spec:
  serviceName: nginx-service #使用哪一个service来管理dns
  replicas: 2
  selector:
    matchLabels:
      app: statefulset-nginx
  template:
    metadata:
      labels:
        app: statefulset-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports: #容器内部暴露的端口
        - containerPort: 80 #端口
        imagePullPolicy: IfNotPresent
      restartPolicy: Always

17.DaemonSet控制器

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

DaemonSet控制器的特点:

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

1.DaemonSet 应用案例

案例:通过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

18.HPA

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

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

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

# 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:
      containers:
      - name: nginx
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

八、Service四层负载均衡

k8s的流量负载组件:Service与ingress,Service用于4层流量的负载,ingress用于7层流量负载。

kubernetes集群中有三类网络,一类是真实存在的,如:Node节点网络、Pod网络,这两种网络均提供真实IP地址。

还有一类是虚拟的Service 网络,提供虚拟cluster IP(VIP)地址,这个地址不会出现在接口上,仅会出现在Service当中。

在kubernetes集群时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务。

Kubernetes中使用了Service来解决这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化 ,只要有Label,就可以让Service能够联系上Pod,进而实现通过Service访问Pod目的。

1.Service常用访问方式介绍
  • ClusterIP:
    • 默认访问方式,分配一个集群内部可以访问的虚拟IP(该方式只能用于集群内部访问,外部无法访问)
  • NodePort:
    • 在每个Node上分配一个端口作为外部访问入口,端口范围为30000-32767(该访问适用于外部访问)
  • LoadBalancer:
    • 通过在集群外部的公有云平台上,例如:阿里云、华为云、AWS等做一个负载均衡,通过外部负载均衡将流量转发到集群中。 访问过程:用户----->域名----->云服务提供商提供LB负载均衡设备----->NodeIP:Port(service IP)---->Pod IP:端口
2.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: 80 #pod中容器的端口
      nodePort: #node端口(Service需要暴露给外部访问的节点端口,端口范围:30000-32767)

3.Cluster IP 应用案例

案例:通过HPA创建3个Pod并设置标签为app=deploy-nginx通过Service ClusterIP访问方式进行代理

# vim hpa-deploy_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  type: ClusterIP #service类型默认访问方式
  ports: #定义端口信息
  - port: 80 #service自己的端口,使用内网ip时使用
    targetPort: 80 #指定pod中容器端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-nginx #标签(需要与代理的Pod标签一致)
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-nginx
  namespace: test
spec:
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 6
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deploy-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
          protocol: TCP
        resources:
          limits:
            cpu: 600m
#创建Pod
kubectl create -f hpa-deploy_nginx.yml
#查看Pod信息
kubectl get pod -n test
#查看Service信息
kubectl get svc -n test
#删除Pod
kubectl delete -f hpa-deploy_nginx.yml

4.NodePort 应用案例

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

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

# vim hpa-deploy_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: test
spec:
  type: NodePort #service类型
  ports: #定义端口信息
  - port: 80 #service自己的端口,使用内网ip时使用
    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
  maxReplicas: 10
  targetCPUUtilizationPercentage: 6
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deploy-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.0
        ports:
        - containerPort: 80
          protocol: TCP
        resources:
          limits: 
            cpu: 600m
#创建Pod
kubectl create -f hpa-deploy_nginx.yml
#查看Pod信息
kubectl get pod -n test
#查看Service信息
kubectl get svc -n test
#删除Pod
kubectl delete -f hpa-deploy_nginx.yml

九、Ingress七层负载均衡

Ingress相当于一个7层的负载均衡器,是k8s对反向代理的一个抽象,它的工作原理类似于Nginx反向代理。提供从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源所定义的规则来控制。

  1. 用户编写Ingress规则,说明哪个域名对应集群中的Service
  2. Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置进行流量转发

1722393428034

1.Ingress 环境搭建

官网地址:https://kubernetes.github.io/ingress-nginx/

1.使用helm安装ingress

安装helm,helm类似于centos中的yum仓库

#下载helm
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
#解压
tar -xf helm-v3.2.3-linux-amd64.tar.gz
#进入解压后的目录
cd linux-amd64
#移动文件到/usr/local/bin/
mv helm /usr/local/bin/
#查看版本
helm version
#添加阿里云helm仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 查看仓库列表
helm repo list
# 搜索 ingress-nginx
helm search repo ingress-nginx

下载ingress包

#下载ingress包
helm pull ingress-nginx/ingress-nginx --version=4.2.5
#解压
tar -xf ingress-nginx-4.2.5.tgz
#进入解压后的包中
cd ingress-nginx

修改配置values.yaml

#镜像地址:修改为国内镜像
registry: registry.cn-hangzhou.aliyuncs.com #总共两处
image: google_containers/nginx-ingress-controller
image: google_containers/kube-webhook-certgen
#注释掉hash校验
digest: sha256:549e71a6ca248c5abd51cdb73dbc3083df62cf92ed5e6147c780e30f7e007a47 #总共两处
digestChroot: sha256:a8466b19c621bd550b1645e27a004a5cc85009c858a9ab19490216735ac432b1
# 增加选择器,如果 node 上有 ingress=true 就部署
修改部署配置的 kind: DaemonSet
找到:nodeSelector:
增加    ingress: "true"
#使用主机的网络模式
hostNetwork: true
#dns策略
dnsPolicy: ClusterFirst 默认集群优先改为 dnsPolicy: ClusterFirstWithHostNet基于主机名
#
将 admissionWebhooks.enabled 修改为 false
#如果服务器是云平台
将 service 中的 type 由 LoadBalancer 修改为 ClusterIP(搜索LoadBalancer)

部署ingress

#创建一个命名空间
kubectl create ns ingress-nginx
# 为需要部署 ingress 的节点上加标签
kubectl label node k8s-master ingress=true
kubectl label node k8s-node1 ingress=true
# 安装 ingress-nginx
helm install ingress-nginx -n ingress-nginx .

查看是否部署成功

kubectl get pod -n ingress-nginx -o wide

1722401549694

2.yml直接安装ingress

官方推荐使用helm安装,如果没有helm可以使用以下方法安装

ingress-nginx资源清单文件下载

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.1/deploy/static/provider/cloud/deploy.yaml

修改deploy.yaml

修改镜像下载地址

创建

#创建ingress-nginx
kubectl create -f deploy.yaml
#查看ns(会有一个ingress-nginx的命名空间)
kubectl get ns
#查看详细信息时会出现如下报错:
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
kubectl get secret -A |grep ingress
复制名字修改yaml中的名字后更新文件
#查看ingress-nginx空间的pod(有两个Pod用于执行一次性任务,状态为Completed(完成),这种Pod执行后即退出。)
kubectl get po -n ingress-nginx

2.Ingress HTTP 应用案例

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

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"
    kubernetes.io/ingress.class: nginx #指定控制器的类别为nginx

spec:
  rules: #定义主机列表
  - host: www.nginx.com #自定义域名
    http:
      paths:
      - pathType: Prefix #路径类型
        path: "/" #定义站点路径,相当于nginx中的location
        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-nginxcontroller-admission.ingressnginx.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


十、configmap与secret

1.ConfigMap

我们在部署应用的时候, 许多应用程序会从配置文件、命令行参数或环境变量中读取所需的配置信息,这些配置信息需要与docker image解耦,不然每修改一个配置就重做一个image 。

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

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

1.使用 ConfigMap 的限制条件:
  • ConfigMap 需要在 Pod 启动前创建出来;
  • 并且只有当 ConfigMap 和 Pod 处于同一命名空间时,才可以被 Pod引用;
  • 当 Pod 挂载 ConfigMap 绑定的目录时,目录下的目录并不会挂载到Pod 内,只有目录下的文件会被挂载。
  • ConfigMap在设计上不是用来保存大量数据的,在ConfigMap中保存的数据不可超过1 MiB,如果你需要保存超出此限制的数据,可以考虑挂载存储卷。
2.ConfigMap创建与使用
# 针对目录创建
kubectl create cm cm-ngx-config --fromfile=/opt/conf.d -n test
#针对具体文件创建
kubectl create cm cm-ngx-config --fromfile=/opt/nginx.conf -n test
kubectl create cm cm-ngx-config --fromfile=nginxcm=/opt/nginx.conf -n test
# 查看
kubectl get cm -n test
# 详情
kubectl describe cm cm-ngx-config -n test

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

#vim 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的名称
            items:
            - key: nginx.conf
              path: etc/nginx/nginx.conf #转换成文件
      containers:
        - name: web-nginx
          image: nginx:1.18-alpine
          ports:
          - containerPort: 80
          volumeMounts: # 定义在容器中挂载的信息
          - name: nginx-config # 挂载的名称(上边定义的卷的名称)
            mountPath: /etc/nginx/nginx.conf # 挂载到容器的路径
            subPath: etc/nginx/nginx.conf #为了防止整个目录给覆盖,不支持热更新

#创建
kubectl create -f cm-nginx-configmap.yml

2.Secret

Secret与与 ConfigMap 类似,用于存储配置信息,但是主要用于存储敏感信息、需要加密的信息,Secret 可以提供数据加密、解密功能。

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

1.Secret有4种类型
  • generic
    • base64编码格式的Secret,用来存储密码、密钥。
  • Service Account
    • 由K8s自动创建,并且会自动挂载到pod的/var/run/secrets/kubernetes.io/serviceaccount目录中
  • docker-registry
    • 用来存储私有docker registry的认证信息,为json格式。
  • tls
    • 用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。
2.创建Secret

方法一

kubectl create secret generic secret-mysql --from-literal=password=MTIzNDU2
#配置一个docker仓库的
kubectl create secret docker-registry harbor-secret --docker-username=admin --docker-passwoed=Admin12345

方法二

vim secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
  namespace: test
data:
  password: MTIzNDU2
#创建
kubectl apply -f secret-mysql.yml
kubectl get secret -test |grep secret-mysql
kubectl describe secret/secret-mysql -n test

3.Secret应用案例
vim secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
  namespace: test
data:
  password: MTIzNDU2
#创建
kubectl apply -f secret-mysql.yml

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

#vim 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
#创建
kubectl apply -f pod-mysql-secret.yml

十一、认证及鉴权

k8s作为一个分布式集群的管理工具,保证集群的安全性是非常重要的任务,所谓的安全性其实就是保证对k8s的各种客户端进行认证和鉴权操作。Kubernetes 中提供了良好的多租户认证管理机制,如 RBAC、ServiceAccount 还有各种策略等。

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

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

1.k8s认证

所有 Kubernetes 集群有两类用户:由 Kubernetes 管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。

  • User Accounts(普通用户)

    • 普通账户是假定被外部或独立服务管理的,由管理员分配 keys,用户像使用 Keystone 或 google 账号一样,被存储在包含 usernames 和 passwords 的 list 的文件里。普通帐户是针对(人)用户的,服务账户针对 Pod 进程。
  • ServiceAccount(服务账户)

    • 指在 kubernetes 集群中的 pod 要访问 apiserver 时所使用的,也就是serviceaccounts。

    • Service Account Admission Controller

      通过 Admission Controller 插件来实现对 pod 修改,它是 apiserver 的一部分。创建或更新 pod 时会同步进行修改 pod。当插件处于激活状态(在大多数发行版中都默认情况)创建或修改 pod 时,会按以下操作执行:
      	如果 pod 没有设置 ServiceAccount,则将 ServiceAccount 设置为 default。
      	确保 pod 引用的 ServiceAccount 存在,否则将会拒绝请求。
      	如果 pod 不包含任何 ImagePullSecrets,则将ServiceAccount 的 ImagePullSecrets 会添加到 pod 中。
      	为包含 API 访问的 Token 的 pod 添加了一个 volume。
      	把 volumeSource 添加到安装在 pod 的每个容器中,挂载在 /var/run/secrets/kubernetes.io/serviceaccount。
      
      
    • Token Controller

      TokenController 作为 controller-manager 的一部分运行。异步行为:
      观察 serviceAccount 的创建,并创建一个相应的 Secret 来允许 API 访问。
      观察 serviceAccount 的删除,并删除所有相应的ServiceAccountToken Secret
      观察 secret 添加,并确保关联的 ServiceAccount 存在,并在需要时向 secret 中添加一个 Token。
      观察 secret 删除,并在需要时对应 ServiceAccount 的关联
      
      
    • Service Account Controller

      Service Account Controller 在 namespaces 里管理ServiceAccount,并确保每个有效的 namespaces 中都存在一个名为 “default” 的 ServiceAccount。
      
      
# 查看Service Account
kubectl get sa -n namespace

2.k8s鉴权及RBAC

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

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

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

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

  • 对象:User、Groups、ServiceAccount(账号)

  • 角色:Role、ClustserRole 代表一个角色,会包含一组权限,没有拒绝规则,只是附加允许。它是 Namespace 级别的资源,只能作用与 Namespace 之内。

    #  查看已有的角色信息
    kubectl get role -n ingress-nginx
    # 查看某个集群角色的信息
    kubectl get clusterrole view
    # 配置文件
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      name: nginx-ingress
      namespace: ingress-nginx
    roles:
    - apiGroups:
      - ""
      resources:
      - configmaps
      - pods
      - secrets
      - namespaces
      verbs:
      - get
    - apiGroups:
      - ""
      resourceNames:
      - ingress-controller-label-nginx
      resources:
      - configmaps
      verbs:
      - get
      - update
    - apiGroups:
      - ""
      resources:
      - configmaps
      verbs:
      - create
    
    
  • 绑定:RoleBinding、ClusterRoleBinding 作用于 Namespace 内,可以将 Role 或 ClusterRole 绑定到 User、Group、Service Account 上。

    # 查看 rolebinding 信息
    kubectl get rolebinding --all-namespaces
    # 查看指定 rolebinding 的配置信息
    kubectl get rolebinding <role_binding_name> --all-namespaces -oyaml
    # 配置文件
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      ......
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name nginx-ingress-role
    subjects:
    - kind: ServiceAccount
      name: nginx-ingress-serviceaccount
      namespace: ingress-nginx
    
    

十二、K8S数据存储

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

1.存储卷的分类

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

# kubectl explain pod.spec.volumes

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

本地存储卷

  • emptyDir(空目录临时存储):pod删除,数据也会被清除, 用于数据的临时存储
  • hostPath:宿主机目录映射(本地存储卷),pod删除,目录中的数据不会被清楚,适合数据的永久保存

网络存储卷 NAS网络附加存储: nfs等 分布式网络附加存储: glusterfs,cephfs,rbd(chph中的存储类型),cinder(OpenStack中的存储类型)等 SAN块存储: iscsi,FC等 云存储: aws,azurefile等

2.本地存储 EmptyDir

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

EmptyDir用途如下:

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

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

#vim emptydir_nginx.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:
      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 #容器内挂载点目录
#创建
kubectl create -f emptydir_nginx.yml

3.本地存储 HostPath

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

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

# vim hostpath_nginx.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:
      volumes: #声明volume存储卷
      - name: nginx-html #定义volume卷名称
        hostpath:  #类型hostPath
          type: DirectoryOrCreate #目录存在就使用,不存在就先创建后使用
          path: /nginx/html #指定node节点目录(存放页面)
      containers:
      - name: nginx
        image: nginx:1.17.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-html #指定挂载的volume名称
          mountPath: /usr/share/nginx/html #容器内挂载点目录
#创建pod
kubectl create -f hostpath_nginx.yml

4.nfs

nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

部署nfs

# 安装 nfs
yum install nfs-utils -y
# 启动 nfs
systemctl start nfs-server
# 查看 nfs 版本
cat /proc/fs/nfsd/versions
# 创建共享目录
mkdir -p /opt/data/k8s-nfs/nginx/html
mkdir -p /opt/data/k8s-nfs/nginx/logs
# 设置共享目录 export
vim /etc/exports
#rw读写,ro只读,192.168.47.0/24允许访问的网段
/opt/data/k8s-nfs/nginx/html 192.168.47.0/24(rw,sync,no_subtree_check,no_root_squash)
/opt/data/k8s-nfs/nginx/logs 192.168.47.0/24(rw,sync,no_subtree_check,no_root_squash)
# 重新加载
exportfs -f
systemctl reload nfs-server
# 到其他测试节点安装 nfs-utils 并加载测试,客户端测不需要启动
yum install nfs-utils -y

mkdir -p /opt/data/nfs/nginx/html
mkdir -p /opt/data/nfs/nginx/logs
mount -t nfs 192.168.47.10:/opt/data/k8s-nfs/nginx/html /opt/data/nfs/nginx/html
mount -t nfs 192.168.47.10:/opt/data/k8s-nfs/nginx/logs /opt/data/nfs/nginx/logs
#取消挂载
umount /opt/data/nfs/nginx/html

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

# vim nfs_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: svc-nfs-nginx
  namespace: test
spec:
  type: NodePort #service类型
  ports: #定义端口信息
  - port: 80 #service自己的端口,使用内网ip时使用
    targetPort: 80 #指定pod中容器端口
    nodePort: #外部访问service的端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-nfs-nginx #和需要代理的pod绑定
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nfs-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-nfs-nginx
  template:
    metadata:
      labels:
        app: deploy-nfs-nginx
    spec:
      volumes: #声明volume存储卷
      - name: nginx-nfs-html #定义volume卷名称
        nfs:  #类型nfs
          server: 192.168.47.10 #NFS服务器地址
          path: /opt/data/k8s-nfs/nginx/html #nfs共享目录
      - name: nginx-nfs-logs #定义volume卷名称
        nfs:  #类型nfs
          server: 192.168.47.10 #NFS服务器地址
          path: /opt/data/k8s-nfs/nginx/logs #nfs共享目录
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-nfs-html #指定挂载的volume名称
          mountPath: /usr/share/nginx/html #容器内挂载点目录
        - name: nginx-nfs-logs #指定挂载的volume名称
          mountPath: /var/log/nginx #容器内挂载点目录
#运行
kubectl apply -f nfs_nginx.yml

5.pv与pvc

持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。

pv状态:

  • Available:空闲,未被绑定
  • Bound:已经被 PVC 绑定
  • Released:PVC 被删除,资源已回收,但是 PV 未被重新使用
  • Failed:自动回收失败

案例:

# vim pv-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: pv-nginx
  namespace: test
spec:
  type: NodePort #service类型
  ports: #定义端口信息
  - port: 80 #service自己的端口,使用内网ip时使用
    targetPort: 80 #指定pod中容器端口
    nodePort: #外部访问service的端口
  selector: #标签选择器(基于标签选择代理的Pod)
    app: deploy-pv-nginx #和需要代理的pod绑定
---
apiVersion: v1
kind: PersistentVolume #资源类型为pv
metadata:
  name: pv-nginx
  namespace: test
spec:
  capacity: #容量
    storage: 5Gi # pv 的具体容量
  volumeMode: Filesystem # 存储类型为文件系统
  accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
    - ReadWriteOnce # 只能被一个pvc使用
  persistentVolumeReclaimPolicy: Recycle # 回收策略 delete Retain
  storageClassName: nginx-html # 创建 PV 的存储类名,需要与 pvc 的相同
  nfs: # 连接到 nfs
    path: /opt/data/k8s-nfs/nginx/html # 存储路径
    server: 192.168.47.10 # nfs 服务地址
---
apiVersion: v1
kind: PersistentVolumeClaim #资源类型为pvc
metadata:
  name: pvc-nginx
  namespace: test
spec:
  volumeMode: Filesystem # 存储类型为文件系统
  accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
    - ReadWriteOnce # 权限需要与对应的 pv 相同
  resources: #最少资源
    requests:
      storage: 3Gi # 资源可以小于 pv 的,但是不能大于,如果大于就会匹配不到 pv
  storageClassName: nginx-html # 名字需要与对应的 pv 相同
#  selector: # 使用选择器选择对应的 pv
#    matchLabels:
#      release: "stable"
#    matchExpressions:
#      - {key: environment, operator: In, values: [dev]}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-pv-nginx
  namespace: test
spec:
  selector:
    matchLabels:
      app: deploy-pv-nginx
  template:
    metadata:
      labels:
        app: deploy-pv-nginx
    spec:
      volumes: #声明volume存储卷
      - name: nginx-pv-html #定义volume卷名称
        persistentVolumeClaim:  #类型nfs
          claimName: pvc-nginx #PVC名称(与前边创建的PVC名称一致)
          readOnly: false #访问模式,false为读写,true为只读
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-pv-html #指定挂载的volume名称
          mountPath: /usr/share/nginx/html #容器内挂载点目录
#执行
kubectl apply -f pv-nginx.yaml

StorageClass

k8s 中提供了一套自动创建 PV 的机制,就是基于 StorageClass 进行的,通过 StorageClass 可以实现仅仅配置 PVC,然后交由 StorageClass 根据 PVC 的需求动态创建 PV。

案列:

# vim storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
  namespace: kube-system
provisioner: fuseim.pri/ifs # 外部制备器提供者,编写为提供者的名称
parameters:
  archiveOnDelete: "false" # 是否存档,false 表示不存档,会删除 oldPath 下面的数据,true 表示存档,会重命名路径
reclaimPolicy: Retain # 回收策略,默认为 Delete 可以配置为 Retain
volumeBindingMode: Immediate # 默认为 Immediate,表示创建 PVC 立即进行绑定,只有 azuredisk 和 AWSelasticblockstore 支持其他值
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
  namespace: kube-system
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: kube-system
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: kube-system
  labels:
    app: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.47.10
            - name: NFS_PATH
              value: /opt/data/k8s-nfs/
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.47.10
            path: /opt/data/k8s-nfs/

PVC 处于 Pending 状态

在 k8s 1.20 之后,出于对性能和统一 apiserver 调用方式的初衷,移除了对 SelfLink 的支持,而默认上面指定的 provisioner 版本需要 SelfLink 功能,因此 PVC 无法进行自动制备。

#解决方式一:配置 SelfLink
修改 apiserver 配置文件
vim /etc/kubernetes/manifests/kube-apiserver.yaml

spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false # 新增该行
    ......

修改后重新应用该配置
kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
#解决方式二:不需要 SelfLink 的 provisioner(推荐)
将 provisioner 修改为如下镜像之一即可
gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0#(推荐)

十三、高级调度

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

k8s提供了四种调度方式:

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

在 k8s 中周期性运行计划任务,与 linux 中的 crontab 相同

注意点:CronJob 执行的时间是 controller-manager 的时间,所以一定要确保 controller-manager 时间是准确的,另外 cronjob

cron 表达式

# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周一;在某些系统上,7 也是星期日)
# │ │ │ │ │                          或者是 sun,mon,tue,web,thu,fri,sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

案列:

# vim cronjob.yaml
apiVersion: batch/v1
kind: CronJob #资源类型
metadata:
  name: cron-job #定时任务名字
spec:
  concurrencyPolicy: Allow # 并发调度策略:Allow 允许并发调度,Forbid:不允许并发执行,Replace:如果之前的任务还没执行完,就直接执行新的,放弃上一个任务
  failedJobsHistoryLimit: 1 # 保留多少个失败的任务
  successfulJobsHistoryLimit: 3 # 保留多少个成功的任务
  suspend: false # 是否挂起任务,若为 true 则该任务不会执行
#  startingDeadlineSeconds: 30 # 间隔多长时间检测失败的任务并重新执行,时间不能小于 10
  schedule: "* * * * *" # 调度策略,多久执行一次
  jobTemplate: #任务模板,任务要做的事情
    spec:
      template:
        spec:
          containers:
          - name: cron-job
            image: busybox:1.28
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

2.初始化容器 InitContainer

在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。

相对于 postStart 来说,首先 InitController 能够保证一定在 EntryPoint 之前执行,而 postStart 不能,其次 postStart 更适合去执行一些命令操作,而 InitController 实际就是一个容器,可以在其他基础容器环境下执行更复杂的初始化功能。

在 pod 创建的模板中配置 initContainers 参数:

spec:
  initContainers:
    - image: nginx
      imagePullPolicy: IfNotPresent
      command: ["sh", "-c", "echo 'inited;' >> ~/.init"]
      name: init-test

3.Pod定向调度NodeName

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

案例:创建pod,并通过节点名称将Pod调度到k8s-node1节点

#vim pod-nodename.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      nodeName: k8s-node1 #定义调度策略,并指定k8s-node1节点
      containers:
      - name: nginx
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:
          protocol: TCP
#创建deploy
kubectl create -f deplo_nginx.yml
#查看deploy详细信息
kubectl get deploy -n test
#删除
kubectl delete -f deplo_nginx.yml

4.Pod 定向调度 NodeSelector

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

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

#打标签
kubectl label node k8s-node2 node=k8s-node2
#查看节点标签
kubectl get node k8s-node2 --show-labels | grep k8s-node2

创建Pod并通过NodeSelector进行调度

# vim deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx
  template:
    metadata:
      labels:
        app: deploy-nginx
    spec:
      nodeSelector: #定义nodeSelector
        node: k8s-node2 #指定节点标签
      containers:
      - name: nginx
        image: nginx:1.20.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:
          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

5.污点和容忍

k8s 集群中可能管理着非常庞大的服务器,这些服务器可能是各种各样不同类型的,比如机房、地理位置、配置等,有些是计算型节点,有些是存储型节点,此时我们希望能更好的将 pod 调度到与之需求更匹配的节点上。

此时就需要用到污点(Taint)和容忍(Toleration),这些配置都是 key: value 类型的。

1.污点

污点:是标注在节点上的,当我们在一个节点上打上污点以后,k8s 会认为尽量不要将 pod 调度到该节点上,除非该 pod 上面表示可以容忍该污点,且一个节点可以打多个污点,此时则需要 pod 容忍所有污点才会被调度该节点。

污点的影响:

  • NoSchedule:
    • 不能容忍的 pod 不能被调度到该节点,但是已经存在的节点不会被驱逐
  • NoExecute:
    • 不能容忍的节点会被立即清除,能容忍且没有配置 tolerationSeconds 属性,则可以一直运行,设置了 tolerationSeconds: 3600 属性,则该 pod 还能继续在该节点运行 3600 秒

为节点打上污点

kubectl taint node k8s-master key=value:NoSchedule

移除污点

kubectl taint node k8s-master key=value:NoSchedule-

查看污点

kubectl describe no k8s-master

2.容忍

容忍:是标注在 pod 上的,当 pod 被调度时,如果没有配置容忍,则该 pod 不会被调度到有污点的节点上,只有该 pod 上标注了满足某个节点的所有污点,则会被调度到这些节点

  • Equal
    • 比较操作类型为 Equal,则意味着必须与污点值做匹配,key/value都必须相同,才表示能够容忍该污点
  • Exists
    • 容忍与污点的比较只比较 key,不比较 value,不关心 value 是什么东西,只要 key 存在,就表示可以容忍。

pod 的 spec 下面配置容忍

tolerations:
- key: "污点的 key"
  value: "污点的 value"
  offect: "NoSchedule" # 污点产生的影响
  operator: "Equal" # 表是 value 与污点的 value 要相等,也可以设置为 Exists 表示存在 key 即可,此时可以不用配置 value

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

# 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:
      tolerations: #添加容忍
      - key: "k8s-node1" #污点的key(必须引起来)
        effect: NoSchedule #污点类型
      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

6.亲和力(Affinity)

亲和力和污点正好相反,亲和力是尽可能部署到那个节点上

亲和性调度与反亲和性调度:

  • NodeAffinity
    • 进行 pod 调度时,优先调度到符合条件的亲和力节点上
  • PodAffinity
    • 将与指定 pod 亲和力相匹配的 pod 部署在同一节点。
  • PodAntiAffinity
    • 根据策略尽量部署或不部署到一块

案列:

# NodeAffinity
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity: # 亲和力配置
    nodeAffinity: # 节点亲和力
      requiredDuringSchedulingIgnoredDuringExecution: # 节点必须匹配下方配置
        nodeSelectorTerms: # 选择器
        - matchExpressions: # 匹配表达式
          - key: topology.kubernetes.io/zone # 匹配 label 的 key
            operator: In # 匹配方式,只要匹配成功下方的一个 value 即可
            values:
            - antarctica-east1 # 匹配的 value
            - antarctica-west1 # 匹配的 value
      preferredDuringSchedulingIgnoredDuringExecution: # 节点尽量匹配下方配置
      - weight: 1 # 权重[1,100],按照匹配规则对所有节点累加权重,最终之和会加入优先级评分,优先级越高被调度的可能性越高
        preference:
          matchExpressions: # 匹配表达式
          - key: another-node-label-key # label 的 key
            operator: In # 匹配方式,满足一个即可
            values:
            - another-node-label-value # 匹配的 value
#      - weight: 20
        ......
  containers:
  - name: with-node-affinity
    image: pause:2.0
# PodAffinity
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity: # 亲和力配置
    podAffinity: # pod 亲和力配置
      requiredDuringSchedulingIgnoredDuringExecution: # 当前 pod 必须匹配到对应条件 pod 所在的 node 上
      - labelSelector: # 标签选择器
          matchExpressions: # 匹配表达式
          - key: security # 匹配的 key
            operator: In # 匹配方式
            values: # 匹配其中的一个 value
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity: # pod 反亲和力配置
      preferredDuringSchedulingIgnoredDuringExecution: # 尽量不要将当前节点部署到匹配下列参数的 pod 所在的 node 上
      - weight: 100 # 权重
        podAffinityTerm: # pod 亲和力配置条件
          labelSelector: # 标签选择器
            matchExpressions: # 匹配表达式
            - key: security # 匹配的 key
              operator: In # 匹配的方式
              values:
              - S2 # 匹配的 value
          topologyKey: topology.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: pause:2.0
# PodAntiAffinity
requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - S1
            topologyKey: topology.kubernetes.io/zone

十四、helm

1.什么是helm

helm是Kubernetes 包管理器,相当于centos中的yum,是查找、分享和使用软件构件 Kubernetes 的最优方式。

Helm 管理名为 chart 的 Kubernetes 包的工具。Helm 可以做以下的事情:

  • 从头开始创建新的 chart
  • 将 chart 打包成归档(tgz)文件
  • 与存储 chart 的仓库进行交互
  • 在现有的 Kubernetes 集群中安装和卸载 chart
  • 管理与 Helm 一起安装的 chart 的发布周期

Helm三个重要的概念:

  • chart 创建Kubernetes应用程序所必需的一组信息。
  • config 包含了可以合并到打包的chart中的配置信息,用于创建一个可发布的对象。
  • release 是一个与特定配置相结合的chart的运行实例。
2.安装helm
#下载helm
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
#解压
tar -xf helm-v3.2.3-linux-amd64.tar.gz
#进入解压后的目录
cd linux-amd64
#移动文件到/usr/local/bin/
mv helm /usr/local/bin/
#查看版本
helm version

3.helm常用命令
helm repo #列出、增加、更新、删除 chart 仓库
helm search #使用关键词搜索 chart
helm pull #拉取远程仓库中的 chart 到本地
helm create #在本地创建新的 chart
helm dependency #管理 chart 依赖
helm install #安装 chart
helm list #列出所有 release
helm lint #检查 chart 配置是否有误
helm package #打包本地 chart
helm rollback #回滚 release 到历史版本
helm uninstall #卸载 release
helm upgrade #升级 release

4.chart 详解
1.目录结构
mychart
├── Chart.yaml
├── charts # 该目录保存其他依赖的 chart(子 chart)
├── templates # chart 配置模板,用于渲染最终的 Kubernetes YAML 文件
│   ├── NOTES.txt # 用户运行 helm install 时候的提示信息
│   ├── _helpers.tpl # 用于创建模板时的帮助类
│   ├── deployment.yaml # Kubernetes deployment 配置
│   ├── ingress.yaml # Kubernetes ingress 配置
│   ├── service.yaml # Kubernetes service 配置
│   ├── serviceaccount.yaml # Kubernetes serviceaccount 配置
│   └── tests
│       └── test-connection.yaml
└── values.yaml # 定义 chart 模板中的自定义配置的默认值,可以在执行 helm install 或 helm update 的时候覆盖

2.Redis chart 实践

修改helm源

# 查看默认仓库
helm repo list
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add aliyun https://apphub.aliyuncs.com/stable
helm repo add azure http://mirror.azure.cn/kubernetes/charts

搜索 redis chart

# 搜索 redis chart
helm search repo redis
# 查看安装说明
helm show readme bitnami/redis

修改配置安装

# 先将 chart 拉到本地
helm pull bitnami/redis
# 解压后,修改 values.yaml 中的参数
tar -xvf redis-17.4.3.tgz
cd redis

# 设置 redis 密码 password
# 修改集群架构 architecture,默认是主从(replication,3个节点),可以修改为 standalone 单机模式
# 修改实例存储大小 persistence.size 为需要的大小
# 修改 service.nodePorts.redis 向外暴露端口,范围 <30000-32767>
# 安装操作
# 创建命名空间
kubectl create namespace redis
# 安装
cd ../
helm install redis ./redis -n redis

查看安装情况

# 查看 helm 安装列表
helm list

# 查看 redis 命名空间下所有对象信息
kubectl get all -n redis

升级与回滚

要想升级 chart 可以修改本地的 chart 配置并执行:
helm upgrade [RELEASE] [CHART] [flags]
helm upgrade redis ./redis
使用 helm ls 的命令查看当前运行的 chart 的 release 版本,并使用下面的命令回滚到历史版本:

helm rollback <RELEASE> [REVISION] [flags]

# 查看历史
helm history redis
# 回退到上一版本
helm rollback redis
# 回退到指定版本
helm rollback redis 3

helm 卸载 redis

helm delete redis -n redis

十五、k8s 可视化界面

在工作中,我们一般不会完全使用命令行去操作k8s,而是通过可视化界面对k8s进行管理。

目前市面上常见的k8s可视化界面组件:

  • Kubernetes Dashboard
    • 这个是k8s官方提供的一个可视化界面,特点:简单,功能简单,直观。缺点:没有那么强大。
  • kubesphere
    • KubeSphere 愿景是打造一个以 Kubernetes 为内核的云原生分布式操作系统,它的架构可以非常方便地使第三方应用与云原生生态组件进行即插即用(plug-and-play)的集成,支持云原生应用在多云与多集群的统一分发和运维管理。https://kubesphere.io/zh/
  • Rancher
    • https://www.rancher.cn/
  • Kuboard
    • https://www.kuboard.cn/
1.Dashboard

安装

# 下载官方部署配置文件
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml


apiVersion: v1
kind: Namespace
metadata:
  name: kubernetes-dashboard

---

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 31286
  selector:
    k8s-app: kubernetes-dashboard

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-certs
  namespace: kubernetes-dashboard
type: Opaque

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-csrf
  namespace: kubernetes-dashboard
type: Opaque
data:
  csrf: ""

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-key-holder
  namespace: kubernetes-dashboard
type: Opaque

---

kind: ConfigMap
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-settings
  namespace: kubernetes-dashboard

---

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
rules:
  # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
    verbs: ["get", "update", "delete"]
    # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["kubernetes-dashboard-settings"]
    verbs: ["get", "update"]
    # Allow Dashboard to get metrics.
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["heapster", "dashboard-metrics-scraper"]
    verbs: ["proxy"]
  - apiGroups: [""]
    resources: ["services/proxy"]
    resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
    verbs: ["get"]

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
rules:
  # Allow Metrics Scraper to get metrics from the Metrics server
  - apiGroups: ["metrics.k8s.io"]
    resources: ["pods", "nodes"]
    verbs: ["get", "list", "watch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kubernetes-dashboard
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: kubernetes-dashboard
          image: kubernetesui/dashboard:v2.7.0
          imagePullPolicy: Always
          ports:
            - containerPort: 8443
              protocol: TCP
          args:
            - --auto-generate-certificates
            - --namespace=kubernetes-dashboard
            # Uncomment the following line to manually specify Kubernetes API server Host
            # If not specified, Dashboard will attempt to auto discover the API server and connect
            # to it. Uncomment only if the default does not work.
            # - --apiserver-host=http://my-address:port
          volumeMounts:
            - name: kubernetes-dashboard-certs
              mountPath: /certs
              # Create on-disk volume to store exec logs
            - mountPath: /tmp
              name: tmp-volume
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /
              port: 8443
            initialDelaySeconds: 30
            timeoutSeconds: 30
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      volumes:
        - name: kubernetes-dashboard-certs
          secret:
            secretName: kubernetes-dashboard-certs
        - name: tmp-volume
          emptyDir: {}
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 8000
      targetPort: 8000
  selector:
    k8s-app: dashboard-metrics-scraper

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: dashboard-metrics-scraper
  template:
    metadata:
      labels:
        k8s-app: dashboard-metrics-scraper
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: dashboard-metrics-scraper
          image: hub.geekery.cn/kubernetesui/metrics-scraper:v1.0.8
          ports:
            - containerPort: 8000
              protocol: TCP
          livenessProbe:
            httpGet:
              scheme: HTTP
              path: /
              port: 8000
            initialDelaySeconds: 30
            timeoutSeconds: 30
          volumeMounts:
          - mountPath: /tmp
            name: tmp-volume
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      volumes:
        - name: tmp-volume
          emptyDir: {}


# 创建资源
kubectl apply -f recommend.yaml

# 查看资源是否已经就绪
kubectl get all -n kubernetes-dashboard -o wide

# 访问测试
https://节点ip:端口

配置所有权限账号

# 创建账号配置文件
touch dashboard-admin.yaml

# 配置文件
apiVersion: v1 
kind: ServiceAccount 
metadata: 
  labels: 
    k8s-app: kubernetes-dashboard 
  name: dashboard-admin 
  namespace: kubernetes-dashboard 
--- 
apiVersion: rbac.authorization.k8s.io/v1 
kind: ClusterRoleBinding 
metadata: 
  name: dashboard-admin-cluster-role 
roleRef: 
  apiGroup: rbac.authorization.k8s.io 
  kind: ClusterRole 
  name: cluster-admin 
subjects: 
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kubernetes-dashboard

# 创建资源
kubectl  apply -f dashboard-admin.yaml

# 查看账号信息
kubectl describe serviceaccount dashboard-admin -n kubernetes-dashboard

# 获取账号的 token 登录 dashboard
kubectl describe secrets dashboard-admin-token-5crbd -n kubernetes-dashboard

2.kubesphere部署
1.在所有节点安装 iSCSI 协议客户端(OpenEBS 需要该协议提供存储支持)
yum install iscsi-initiator-utils -y
# 设置开机启动
systemctl enable --now iscsid
# 启动服务
systemctl start iscsid
# 查看服务状态
systemctl status iscsid

2.安装 OpenEBS
kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
# 查看状态(下载镜像可能需要一些时间)
kubectl get all -n openebs

1722836793431

3.创建本地存储
#vim default-storage-class.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local
  annotations:
    cas.openebs.io/config: |
      - name: StorageType
        value: "hostpath"
      - name: BasePath
        value: "/var/openebs/local/"
    kubectl.kubernetes.io/last-applied-configuration: >
      {"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"cas.openebs.io/config":"-
      name: StorageType\n  value: \"hostpath\"\n- name: BasePath\n  value:
      \"/var/openebs/local/\"\n","openebs.io/cas-type":"local","storageclass.beta.kubernetes.io/is-default-class":"true","storageclass.kubesphere.io/supported-access-modes":"[\"ReadWriteOnce\"]"},"name":"local"},"provisioner":"openebs.io/local","reclaimPolicy":"Delete","volumeBindingMode":"WaitForFirstConsumer"}
    openebs.io/cas-type: local
    storageclass.beta.kubernetes.io/is-default-class: 'true'
    storageclass.kubesphere.io/supported-access-modes: '["ReadWriteOnce"]'
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

# 在主节点创建本地 storage class
kubectl apply -f default-storage-class.yaml

1722836845547

4.开始部署
kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.3.1/kubesphere-installer.yaml


kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.3.1/cluster-configuration.yaml


#查看日志
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f


3.Rancher
docker run --privileged -itd --restart=unless-stopped -p 81:80 -p 1443:443 -v /home/rancher:/var/lib/rancher/:rw  --name "rancher" rancher/rancher:v2.5.8

十六、实战项目

apiVersion: v1
kind: PersistentVolume #资源类型为pv
metadata:
  name: blog-pv
  namespace: kube-devops
spec:
  capacity: #容量
    storage: 5Gi # pv 的具体容量
  volumeMode: Filesystem # 存储类型为文件系统
  accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
    - ReadWriteOnce # 只能被一个pvc使用
  persistentVolumeReclaimPolicy: Recycle # 回收策略 delete Retain
  storageClassName: blog # 创建 PV 的存储类名,需要与 pvc 的相同
  nfs: # 连接到 nfs
    path: /opt/data/k8s-nfs/blog/static/assets/ # 存储路径
    server: 192.168.134.110 # nfs 服务地址
---
apiVersion: v1
kind: PersistentVolumeClaim #资源类型为pvc
metadata:
  name: blog-pvc
  namespace: kube-devops
spec:
  volumeMode: Filesystem # 存储类型为文件系统
  accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
    - ReadWriteOnce # 权限需要与对应的 pv 相同
  resources: #最少资源
    requests:
      storage: 3Gi # 资源可以小于 pv 的,但是不能大于,如果大于就会匹配不到 pv
  storageClassName: blog # 名字需要与对应的 pv 相同
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: blog-deployment
  name: blog-deployment
  namespace: kube-devops
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: blog-deployment
  strategy:
    rollingUpdate:
      maxSurge: 100%
      maxUnavailable: 100%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: blog-deployment
    spec:
      imagePullSecrets:
        - name: harbor-secret
      containers:
        - name: blog-deployment
          image: REGISTRY/DOCKERHUB_NAMESPACE/APP_NAME:TAG_NAME
          readinessProbe:
            httpGet:
              path: /
              port: 8080
            timeoutSeconds: 10
            failureThreshold: 30
            periodSeconds: 5
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              protocol: TCP
          resources:
            limits:
              cpu: 300m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 100Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - name: blog
              mountPath: /app/static/assets/
      volumes:
        - name: blog
          persistentVolumeClaim:
            claimName: blog-pvc
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: blog-service
  name: blog-service
  namespace: kube-devops
spec:
  ports:
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: blog-deployment
  sessionAffinity: None
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  name: blog-service-clusterip
  namespace: kube-devops
spec:
  selector:
    app: blog-deployment
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-ingress #自定义ingress名称
  namespace: kube-devops
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
    kubernetes.io/ingress.class: nginx #指定控制器的类别为nginx
spec:
  rules: #定义主机列表
    - host: www.blog.com #自定义域名
      http:
        paths:
          - pathType: Prefix #路径类型
            path: "/" #定义站点路径
            backend: #定义后端引用的服务
              service: #关联service
                name: blog-service-clusterip #对应上面创建的service名称
                port:
                  number: 8080 #service端口

k8s
  • 作者:shi(联系作者)
  • 发表时间:2024-08-14 11:09:35
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论