k8s

查看服务器上k8s组件版本

rpm -qa | grep kube

降级

yum downgrade kubeadm-1.23.1-0.x86_64 kubectl-1.23.1-0.x86_64 kubelet-1.23.1-0.x86_64

part1 在三台虚拟机上搭建k8s集群

1.1 设置三台主机静态网卡固定ip

192.168.16.136 --主节点

192.168.16.137 --node1 工作节点

192.168.16.138 --node2 工作节点

1.2 关闭防火墙

三台虚拟机全部执行

++不关闭防火墙就要开启服务所需的端口

systemctl stop firewalld #临时关闭防火墙
​
systemctl disable firewalld.service #永久关闭防火墙
​
iptables -F #关闭iptables,但是centos7默认关闭iptables
​
setenforce 0 #关闭selinux

++正则表达式的应用--此处用的是基础正则表达式,感兴趣可以学习一下扩展型正则表达式

grep  -n "enforcing" /etc/selinux/config #grep搜索文档里的enforcing并显示在第几行,也可以用cat -n xxx显示内容并显示第几行
sed -i "7s/ENFORCING/disable/ " /etc/selinux/config   #修改SELINUX=ENFORCING为SELINUX=disable
sestatus #查看selinux状态

++搭建集群所需端口

image-20230423143349302

1.3 设置三台主机名

方便后续管理

hostnamectl set-hostname master #主节点
hostnamectl set-hostname node1  #工作节点
hostnamectl set-hostname node2  #工作节点
bash  #立即生效

1.4 添加内网映射关系

三台虚拟机全部执行

++ 涉及到pod通信这一重要概念,所以先了解一下

在Kubernetes集群中,Pod会被分配到一个Node上,并且每个Pod都有自己唯一的IP地址,用于与其他Pod通信。但是,当多个节点(Node)存在时,这些节点之间必须通过网络进行通信。因此,在搭建Kubernetes集群时,必须考虑网络通信的问题。

创建内网映射关系可以让集群中的节点通过内网互相访问,不用经过外部网络,当一个pod需要与另一个pod通信时,它只需要使用目标pod的ip地址,而不需要知道它所在节点的ip地址,使pod之间的通信更加方便和可靠,创建内网映射关系可以有效解决k8s集群中的网络通信问题,提高集群的可用性和安全性

vim /etc/hosts
​
192.168.16.136 master
192.168.16.137 node1
192.168.16.138 node2
​
​
cat <<EOF >> /etc/hosts
192.168.16.136 master
192.168.16.137 node1
192.168.16.138 node2
EOF

image-20230423114758564

1.5 关闭swap分区

三台虚拟机全部执行--必须

++ swap分区 --(扩展:linux中各个分区的作用)

swap分区是linux系统中用于缓解内存压力的一种机制,当系统的物理内存(RAM)不足时,linux系统会将一部分不常用的内存数据转移到swap分区中,以便腾出更多的物理内存来使用。swap分区可以是专门的磁盘分区,也可以是特定文件系统上的交换文件。使用swap分区有助于防止系统因为内存不足二崩溃或无法执行重要的任务,但同时也可能会对系统的性能产生一定的影响。因为磁盘I/O速度远远慢于物理内存,所以当系统使用Swap分区时,读写速度会变得较慢,从而可能会降低系统的响应速度。

在k8s中建议关闭swap分区:在Kubernetes集群中使用交换分区可能会导致节点无响应或运行缓慢,关闭交换分区可以减少系统出现OOM(Out of Memory)错误的风险。

关闭交换分区可以确保系统只使用物理内存,从而提高系统的整体性能。

swapoff -a #临时关闭
vim /etc/fstab  #该文件包含有关文件系统、它们的挂载点、挂载选项和其他参数的信息。
将swap分区注释掉
##/dev/mapper/centos-swap swap                    swap    defaults        0 0
​
练习正则表达式sed工具
先使用grep命令
grep -n "swap" /etc/fstab --查找swap分区在第几行
再使用sed命令在行首添加#
sed -i '11s/^/#/' /etc/fstab
查看swap分区是否关闭成功
free -m

image-20230423140938511

1.6 同步网络时间

三台虚拟机全部执行

ntpdate ntp1.aliyun.com

基础环境准备完毕,安装k8s集群需要的工具

1:容器运行时:可以使用docker或者是containerd,用于在虚拟机中运行容器,本文档里使用的是docker

2:kubeadm工具:用于创建和初始化kubernetes集群,kubeadm会自动安装和配置必要的组件,包括kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy等。

3:kubectl工具:用于与kubernetes API交互并管理kubernetes集群。

4:kubelet服务:在每个节点上运行,管理容器的生命周期和资源。

5:网络插件:此处用的是flannel,用于提供容器网络和跨节点通信。

1.7 安装docker

三台虚拟机全部执行

++docker在kubernetes中的作用是提供一种标准化的容器方案,使应用程序的部署和管理变得更加简单和可靠。

添加指定的docker源

yum install yum-utils -y
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安装:若安装指定版本 docker 可运行 yum list docker-ce --showduplicates | tail -n 10 查看版本号

image-20230423111732729

yum install docker-ce -y  #若出现error无法下载,重复执行该命令

image-20230423112145759

image-20230423112307076

查看当前docker版本

docker -v

image-20230423112058824

1.8 安装kubeadm、kubelet、kubectl

三台虚拟机全部执行

++kubeadm是一个快捷搭建kubernetes的安装工具,它提供了kubeadm init以及kubeadm join这两个命令来快速创建kubernetes集群,kubeadm会自动安装和配置必要的组件。

++kubelet实在每个node节点上运行的主要的”节点代理“,主要职责是确保容器在节点上按预期运行,kubelet与kubernetes API服务器通信,接收有关运行那些容器以及他们应如何配置的指令。

++kubectl:kubectl是k8s命令行工具,用于与kubernetes api进行交互,例如创建和管理kubernetes资源对象,查看集群状态。

验证每个节点的mac地址和product_uuid是否唯一,如果不唯一安装过程可能失败
cat /sys/class/dmi/id/product_uuid

检测所需端口是否打开(防火墙和selinux已经关闭可以忽略)

firewall-cmd --query-port=8080/tcp #检测8080端口是否打开
firewall-cmd --add-port=8080/tcp #打开8080端口
firewall-cmd --remove-port=8080/tcp #关闭8080端口

添加k8s yum源

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

安装:不要安装最新版

指定版本安装:不要安装过高版本,初始化会报错

yum list kubeadm --showduplicates -y | sort -r #获取版本列表
yum list kubelet --showduplicates -y | sort -r
安装1.23.1
yum install -y kubelet-1.23.1 kubeadm-1.23.1 kubectl-1.23.1

docker、kubelet启动并配置开机自启

systemctl enable kubelet && systemctl start kubelet
systemctl enable docker && systemctl start docker

image-20230423145031238

修改docker配置

官方建议修改 docker Cgroup Driver 为 systemd

cat <<EOF > /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": ["https://m24eqnhh.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload && systemctl restart docker --重启

查看是否修改成功

grep "systemd" /etc/docker/daemon.json

image-20230423145336924

1.9 kubernetes初始化集群:(只在主节点跑!!!)

++初始化集群的作用:将主节点和工作节点组成一个完整的kubernetes集群,使用kubernetes init初始化主节点安装kubernetes组件、生成证书和密钥、创建默认的服务账户和角色绑定等,初始化主节点后可以使用kubeadm join命令将其它节点加入到kubernetes集群中,形成完整的集群。

kubeadm init \
--apiserver-advertise-address=192.168.16.136 \ #换成自己的主节点ip
--image-repository registry.aliyuncs.com/google_containers \ #镜像仓库地址
--kubernetes-version=v1.23.1 \ #版本,非常重要,如果你安装的不是1.23.1版本,需要修改成自己的版本
--pod-network-cidr=10.244.0.0/16 \ #网络配置选项,用于指定集群中容器所使用的IP地址的范围。在配置使用的网络插件时要注意配置的ip地址范围和其匹配
--service-cidr=10.96.0.0/16 #把网段分配给service服务,sevice服务可以把pod和node的网络地址暴露出来,让外部可以访问
​
​
kubeadm init  --apiserver-advertise-address=192.168.16.136 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.1 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/16 

这里会卡住一会,正常

image-20230522092409279初始化完成后会获取到一个token值,需要记录下来,使node节点加入集群

image-20230423163155992

kubeadm join 192.168.16.136:6443 --token bvjytp.gvx9f7521e2sqzhz \
    --discovery-token-ca-cert-hash sha256:1ab7a32f3d4d187a1d4957685a04b73c0ecd5c03dbcdca99a3d7c7569e366be5

管理token

kubeadm token create --print-join-command --ttl=0 #永不过期
kubeadm token list #查看是否有存活的 token
systemctl status kubelet #查看 kubelet 有没有启动(初始化失败会启动失败,初始化成功会自动重启)
kubectl get pods -n kube-system #查看系统 pod 运行状态
kubectl describe pod [pod-name] -n kube-system #查看系统 pod 启动详情
journalctl -xefu kubelet #查看 kubelet 启动日志

master节点

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/profile #将Kubernetes集群的配置文件路径添加到环境变量中的命令。配置文件包括:集群的认证信息和相关配置,例如 API Server 的地址、证书和密钥等信息,这个文件通常只对管理员用户可见,用于管理和配置集群的各种资源和服务。
source /etc/profile  #让系统立即读取并执行profile文件中的配置,使得当前shell环境中的变量都能够访问到这个配置

node节点

mkdir -p $HOME/.kube #node 节点执行
scp /etc/kubernetes/admin.conf root@node1:/root/.kube/config #master 节点
#工作节点执行,将文件所属用户和组修改为当前用户
chown $(id -u):$(id -g) $HOME/.kube/config #node 节点

集群初始化的过程中,'kubeconfig'文件发生了什么? --/kube/config

首先,它是由哪个命令生成的?什么是kubeconfig?里面存放了什么信息?

kubeconfig是集群中用来配置kubectl命令行的工具。包含了用于链接kubernetes api服务器的配置信息,包括集群信息、用户信息、以及上下文信息等

集群初始化时使用的kubeadm init命令中' --apiserver-advertise-addr0ss=192.168.16.136'执行时就生成了kubeconfig,此时kubeconfig存放在'/etc/kubernetes/admin.conf'文件中

image-20230427114841200

然后在工作节点执行'mkdir -p $HOME/.kube'创建一个文件夹,执行scp /etc/kubernetes/admin.conf root@node1:/root/.kube/config将kubernetes集群的配置文件admin.conf复制到节点的/root/.kube/config文件中,让node节点上的kubelet组件可以通过admin.conf文件访问到kubernetes集群中的API server,并获取集群中的资源信息。

image-20230427115046900

在默认情况下,kubectl命令会在$HOME/.kube/config文件中查找kubeconfig配置文件,如果需要使用不同的kubeconfig配置文件,可以使用--kubeconfig选项来指定文件的路径,例如:

kubectl --kubeconfig=myconfig.yaml get pods

node节点加入集群 --把token换成自己的

#master节点初始化后获得的token
kubeadm join 192.168.16.136:6443 --token bvjytp.gvx9f7521e2sqzhz \
    --discovery-token-ca-cert-hash sha256:1ab7a32f3d4d187a1d4957685a04b73c0ecd5c03dbcdca99a3d7c7569e366be5 

查看集群中的节点

kubectl get nodes

image-20230423163419107

集群搭建成功

part2 实现节点以及pod之间的网络通信--flannel

集群初始化时有个提示是让你安装集群中实现网络通信的yaml文件

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

image-20230427143148994

有很多网络插件都可以为集群提供网络通信服务,本文档中使用的是flannel

下载安装flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
在docker里查看flannel++要等一段时间才能在列表中看到
docker images

image-20230426000746678

等到node通信,节点状态变成ready

kubectl get node 

image-20230426000831618

part3 部署可视化工具

3.1 dashboard安装

dashboard是基于网页的kubernetes用户界面,可以使用dashboard将容器应用部署到kubernetes集群中,也可以对容器应用排错以及管理集群资源

mkdir dashboard  #创建文件夹
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml   #下载dashboard的yaml文件
vim recommended.yaml   #修改dashboard的yaml文件
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001   #设置dashboard的运行端口
  type: NodePort   #把网络暴露出来,使外部能访问
  selector:
    k8s-app: kubernetes-dashboard

此处涉及到yaml以及nodeport概念

#将dashboard部署到k8s集群中
kubectl apply -f recommended.yaml 
#查看部署进度
kubectl describe svc,pods  -n kubernetes-dashboard

image-20230426002216052

#查看dashboard状态
kubectl get svc,pods  -n kubernetes-dashboard

image-20230426002300165

#dashboard在部署完成并且运行中,通过集群中节点ip地址:30001端口访问**不要忘记加https**
https://ip:30001

image-20230426002427582

kubectl get serviceaccounts --namespace=kubernetes-dashboard   #查看dashboard的用户列表
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard-token | awk '{print $1}')    #查看默认用户的token值

3.2 管理员用户及资源管理

使用默认用户的token值登录dashboard --由于默认用户权限不足,查看不到集群中的资源

image-20230427145730972

创建管理员账户

kubectl create serviceaccount liqy   #创建账户liqy
kubectl create clusterrolebinding liqy-cluster-admin --clusterrole=cluster-admin --serviceaccount=default:liqy   #授权
kubectl get secret $(kubectl get serviceaccount liqy -o jsonpath='{.secrets[0].name}') -o go-template='{{.data.token | base64decode}}'   #获取token值

image-20230427150239118

获取到token值后登录dashboard

image-20230427150250938

至此,k8s集群以及节点之间的互相通信和可视化界面搭建完成。

part4 pod、deployment、service

k8s集群中的重要概念包括cluster、node、pod、namespace、deployment、service等,下面会进行详细介绍以及它们在哪里发挥作用。

4.1 要了解kubernetes,先要了解什么是容器化

容器化:容器化是将应用程序及其依赖项封装到一个独立的运行环境中,以便可以轻松的在不同的计算机和操作系统上进行部署和运行,所有容器共享主机的系统,是一种轻量级虚拟化技术,性能损耗少、资源隔离、cpu和内存可按需分配。

容器化部署图示:

image-20230427155410104

container runtime(容器运行时):常见的容器运行时包括docker、rkt、containerd等,负责管理容器的创建、启动、停止和销毁等生命周期,并通过操作系统提供的系统调用来实现容器与宿主机之间的隔离和资源管理。在kubernetes等容器编排平台中,通常会使用容器运行时来管理容器的创建和运行,以便在集群中实现高效的容器部署和管理。

容器编排指的是通过编排工具对容器进行管理和调度,将多个容器组合成一个完整的应用程序并进行自动化部署、扩展和管理的过程,在容器化应用程序的部署过程中,容器编排工具可以协调管理多个容器之间的依赖关系、网络通信、负载均衡、自动伸缩等问题,简化应用程序部署和管理的复杂度,提高应用程序的可靠性和可维护性。

值得注意的是,目前公司使用的slurm调度系统虽然支持使用容器,但它不是一种专门的容器编排工具。

4.2 kubernetes概念

kubernetes集群是做什么的?什么场景下需要搭建kubernetes集群?kubernetes和docker之间的关系?

kubenertes集群是一个为容器化应用提供集群部署和管理的开源工具,它可以自动化部署、扩展和管理容器化应用程序,当应用只需要跑在一台机器上时,使用docker就可以完成,当应用需要跑在3、4台机器上,可以使用负载均衡工具管理它,当机器逐渐增加几十几百台时,每次加机器会变得非常困难,使用kubernetes可以提供集中式的管理集群机器和应用,加机器、版本升级、版本回滚都可以一键完成,并且kubernetes可以提供不停机的灰度更新,确保高可用、高性能、高扩展。后面部分会有灰度更新的实验

kubernetes使用docker进行编排,也可以使用其它容器管理工具,k8s解决了单独使用docker的若干缺点:

1.容器上升,管理成本高

2.没有有效的容灾、自愈机制

3.没有图形化管理工具

4.没有预设编排模板,无法实现快速、大规模容器调度

......

k8s基础架构:

其中,master是主节点,worker是工作节点

主节点不需要很高的性能,不跑任务,通常只有一个,也可以开多个主节点提高集群可用性。

工作节点可以是虚拟机或物理计算机,需要跑任务,机器性能较好,通常都有很多个,可以不断加机器扩展集群,工作节点由主节点管理。

master

worker1

worker2

worker3

worker...

cluster

在集群中有时会出现cluster,例如集群初始化过程中提示你需要在‘cluster’里安装一个网络插件,cluster通常用来代指kubernetes,所以在使用kubernetes集群时出现‘需要对cluster’进行操作的提示,就是需要在集群中进行操作。

4.3 apiVersion

关于后续创建pod和管理pod时配置中的'apiVersion'问题

创建pod时字段为'apiVersion: v1',创建deployment时字段为'apiVersion: apps/v1'

这是因为pod和deployment使用的是不同的api组,pod属于core API Group,deployment属于apps API Group。

core API Group是kubernetes中最基本、最核心的API Group,也是默认API Group。它包含了kubernetes中最基本的API资源,如pod、service、namespace、node、secret等,是其它api group的基础,在没有指定api group的情况下,kubernetes默认使用core API Group。

apps API Group包含了用于管理部署、副本集、守护进程集等应用级别资源的API对象,这些API对象提供了许多有用的功能,例如自动化应用的水平扩展和滚动升级等,通过使用apps API组,用户可以方便地管理和控制其应用程序的生命周期。

还有许多其他类型的API,这些API可以在Kubernetes API文档中找到。

下面通过在集群中部署nginx服务,并使其可以通过外部客户端访问来理解pod、deployemnt、service三者之间的关系

4.4 Pod--kubernetes中重要概念!!!

1.pod(豆荚) :k8s调度管理的最小单位,一个pod可以包含一个或者多个容器,这些容器共享同一个网络命名空间、存储卷和其他资源,他们可以相互通信和协作。每个pod都有自己的虚拟ip(麻烦复习一下flannel),一个工作节点可以有多个pod,主节点会考量负载自动调度pod到哪个节点运行

负责调度和决定将pod调度到那个节点的组件是kubernetes调度器(scheduler),调度器基于一组配置策略和条件来选择合适的节点来运行。

2.pod作为kubernetes中最基本的调度和管理单位,它可以被创建、部署、扩容、升级和删除

3.kubernetes中docker和pod之间的关系:docker和pod是两个不同的概念,pod是kubernetes中的一个抽象层,是容器编排和管理的最小单位,而docker是一个用于创建和管理容器的工具,是实现容器化的基础技术之一。

4.pod的生命周期是有限的,它的生命周期包括了创建、运行和销毁三个阶段,在运行过程中,pod可能会由于容器崩溃、节点故障、kubernetes集群升级等原因重启。

一个pod里可以包含多个容器,为容器之间的通信提供了基础设施,而docker提供了容器的构建、打包和运行环境

image-20230526135112141

为什么docker ps命令看不到容器:在单独使用docker时可以通过docker ps查看正在运行的容器,但是在kubernetes集群中,pod中的容器是由kubelet直接通过docker api在node节点上启动的,而不是通过docker ps命令启动的,因此在node节点上使用docker ps看不到pod中的容器。

4.4.1 创建pod

创建pod要先掌握.yaml文件,通过创建和配置.yaml文件来创建pod

yaml是一种用于序列化数据的格式,不是一种编程语言,它的设计宗旨是方便人类阅读和编写,并且易于机器解析和生成,yaml文件使用缩进、键值和列表等简单的语法,类似于json,但更ASZ不了测试sanjmedytyyyyytytytyty为灵活和易读。

yaml常用于配置文件、数据交换格式和存储数据等场景,在kubernetes中,yaml文件通常用于定义pod、service、deployment等kubernetes资源对象的配置信息。可以使用任何文本编辑器编写yaml文件,但是需要遵循yaml的语法规则,以确保文件能够正确解析和应用。

编写yaml文件时一定要注意缩进问题

实战:使用kubectl创建pod

vim nginx-pod.yaml
apiVersion: v1        #指定所使用的kubernetes API的版本,必须指定合法的值
kind: Pod             #指定要创建的资源对象类型,必须是kubernetes支持的合法类型
metadata:             #指定pod的元数据信息,包括容器名称、容器镜像、容器端口等信息
  name: nginx         #指定容器名称,必须指定
  labels:             #指定容器标签,不指定会是default,最好指定一下
    app: nginx        #标签名为‘app’,值为‘nginx’
spec:                 #指定pod中的容器规范信息,包括容器名称、容器镜像、容器端口等信息
  containers:         #容器信息
  - name: nginx       #容器名称,必须指定,不指定会导致集群无法识别容器
    image: nginx:alpine   #镜像版本
    ports:                #指定端口
    - containerPort: 80   #容器运行的端口
kubectl apply -f nginx-pod.yaml #将pod部署到集群中

4.4.2 pod内的配置

分解:

metadata:             #指定pod的元数据信息,包括容器名称、容器镜像、容器端口等信息
  name: nginx         #指定容器名称,必须指定
  labels:             #指定容器标签,不指定会是default,可以不指定但是最好指定一下
    app: nginx  

关于pod里容器标签,标签是kubernetes集群中非常重要的概念,用于表示和分类各种资源对象(如pod、service、deployment等),通过为资源对象添加标签,可以方便地对它们进行筛选、查找和管理,从而实现更加灵活和高效的资源管理。

在上述实例中,这个pod的标签信息可以用来识别它所属的应用程序,以及与其它相关资源(如service和deployment(service、deployment和pod之间的关系会在接下来的部分提到))建立关联关系。例如可以通过这个标签选择所有使用”nginx“应用程序的pod,并对他们进行批量管理。

ports:                #指定端口
- containerPort: 80   #容器运行的端口

可以不指定,如果不指定容器运行的端口,kubernetes会自动为容器创建一个名为”default“的端口,并将它映射到容器内部的端口,此时如果容器内部运行的应用程序监听的端口为80,则kubernetes会将容器的80端口映射到”default“端口,从而允许通过容器的的IP地址访问应用程序。

如果容器默认运行的端口不是80,那必须在pod里指定默认端口吗?

是否可以不指定pod里容器的默认端口要看具体情况,如果容器有自己默认的运行端口并且pod内的端口不互相冲突则可以不指定,但是最好是指定端口。

如果容器默认端口是80,我可以在pod里指定它的运行端口是xxx吗?

可以的

ports:                #指定端口
- containerPort: xxx   #容器运行的端口

这将在pod内部的容器中将端口xxx映射到容器默认端口80,是个端口转发的过程。

关于将指定端口映射到容器默认端口的思考,实验,将pod里的nginx容器运行端口指定为445

如果容器默认端口是80,在pod里指定它的运行端口是443

进容器查看nginx服务运行使用的端口

kubectl exec -it nginx sh
netstat -ntlp

image-20230504112859485

在集群中查看端口占用

kubectl describe pod nginx |grep "Port"

image-20230504113159700

可以看出,指定nginx运行端口为445后,集群中nginx占用的是445,但是在容器内部,nginx还是运行在80端口上的,所以在集群中访问445是转发到了容器内部的80端口上。通过这个转发实现了访问445端口获取到nginx的资源。

查看pod运行的节点和pod的ip

kubectl get pods -o wide

image-20230504115821535

关于集群内部使用podip访问pod的问题

在flannel部分提到,flannel给每个pod分配ip,在kubernetes中,默认情况下,所有pod之间的网络是开放的,如果不设置网络策略,那么一个pod就可以通过它的IP地址和端口访问到另外一个pod

如:进入nginx容器访问其它pod里的容器,证明pod之间可以互相通信

image-20230504130202330

同样,在集群中可以通过pod的ip地址和端口号访问

curl 10.244.1.6:80

image-20230504130427476

但是,尽管我们在创建pod时将容器运行的端口号改为445,依然不能通过"curl 10.244.1.6:445"获取到pod里的资源,这是因为,当使用podip+端口号访问时,如果端口号与容器内的端口号一致,则会将请求转发到容器内对应的端口,如果端口号与容器内的端口号不一致,则无法连接到容器内的服务,需要配置service将端口号暴露出来。

4.4.3 pod的删除

kubectl get pod                 #查看pod
kubectl delete pod pod-name     #删除pod

注意:如果pod创建了对应的deployment和service,要一起删除

通过delete删除pod,如果使用的是空白卷,删除pod时数据也会被删除,如果使用的是持久卷,删除pod时,数据将保留在持久卷中,可以在以后的pod中重新挂载该持久卷

特权模式

权模式下po d可以访问宿主机的所有资源,包括设备和文件系统等,这使得容器可以执行更高级别的任务,但同时也会增加安全风险。

给pod赋予特权模式

...
image: nginx:alpine   #镜像版本
    ports:                #指定端口
    - containerPort: 80
 securityContext:
        privileged: true

特权模式pod和非特权模式pod可用设备列表

image-20230424213340487

让pod可以使用主机的yum仓库

apiVersion: v1
kind: Pod
metadata:
  name: centos-yum
spec:
  hostNetwork: true 
  containers:
  - name: centos
    image: centos:7     --主机使用的镜像
    command: ["/bin/bash", "-c", "while true; do sleep 3600; done"] --让pod一直运行
    securityContext:
      privileged: true 
    volumeMounts:
    - name: host-yum
      mountPath: /etc/yum.repos.d/   --主机yum源
      readOnly: true
  volumes:
  - name: host-yum
    hostPath:
      path: /etc/yum.repos.d/  --主机yum仓库存储路径

image-20230425091148959

4.5 pod的管理--deployment(部署)

4.5.1 deployment

概念:deployment控制器并不直接管理pod,而是通过管理Replicaset管理pod

Replicaset是pod控制器类型的一种实现,用于确保由其管控的pod对象副本数在任一时刻都能精确满足期望的数量,replicaset控制器资源启动后会查找集群中匹配其标签选择器的pod资源对象,当前活动的对象数量与期望的数量不吻合时,多则删除,少则通过pod模板创建以补足。等pod资源副本数量符合期望值后即进入下一轮和解循环,ReplicaSet的副本数量、标签选择器甚至是Pod模板都可以随时按需进行修改。

deployment

Replicaset

pod1

pod2

pod3

deployment的主要功能有:

支持replicaset的所有功能

支持发的停止、继续

支持版本的滚动更新和版本回退 --滚动,可以理解为灰度的一种

++创建pod时不一定要创建deployment,但是pod本身比较脆弱,不具备高可用性,如果一个pod被删除,那么它将永远消失,并且pod不能自我修复,如果出现故障,只能手动删除它并创建一个新的pod

创建deployment,管理上一步中创建的pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec: 
  selector:          #spec.selector:用于定义 deployment 如何查找要管理的                                         pod,例如,使用在 pod                                           模板中定义的标签,如 app:nginx
    matchLabels:
      app: nginx     
  replicas: 3       #spec.replicas:用于定义需要启动多少个副本,并确保pod一直运行在集群中
  template:         #spec.template:用于定义 pod 的属性,例如,容器名称,容器镜像,labels 字段,等
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
kubectl apply -f nginx-dep.yaml #将deployment部署到集群中

拆解

matchLabels:
  app: nginx  

matchLabels是deployment中的一个重要字段,用来匹配要管理的pod,此处联动pod里的标签一起理解,当使用deployment进行滚动更新,版本回滚时,只会对匹配该标签的pod进行操作。

replicas: 3       #spec.replicas:用于定义需要启动多少个副本,并确保pod一直运行在集群中
kubectl get pod #可以看到已经创建了三个nginx副本

image-20230504144447714

 template:     #模板
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 445

deployment控制器所创建的pod时根据pod模板来生成的,因此’template‘部分定义的内容会应用于所有由deployment创建的pod中,包括容器的镜像和端口号等信息,因此,如果在deployment中定义的端口号和pod模板中定义的不一样,最终生成的pod中会使用pod模板中定义的端口号。

4.5.2 deployment版本滚动更新实验

kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort | uniq  #查看集群中的nginx版本
kubectl get deploy -o wide #查看集群中的deployment

image-20230504150824709

使用set image模式更新
kubectl set image deployment/nginx-deployment nginx=nginx:latest
使用rollout查看更新过程
kubectl rollout status deployment/nginx-deployment
查看更新结果
kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort | uniq

image-20230504151959116

说明:kubernetes采用的是滚动更新的方式,不会立刻删除旧的pod,而是先创建新的pod,然后逐步地停止旧的pod,直到所有的pod都被更新为止。

4.6 pod的网络服务--service

在kubernetes中,pod是容器化应用的基本单位,每个pod都有一个唯一的ip地址,但是pod的生命周期是有限的,当pod被删除、重新调度或者更新时,它的ip地址也会被回收,因此无法长期提供服务。

service提供了一种稳定的IP地址和DNS名称,可以让应用程序以相同的方式来访问一组pod,service还可以负责将请求路由到正确的pod,并提供负载均衡、服务发现等功能。

Service还用于暴露应用程序的网络服务,并允许它们在集群内和集群外进行访问

创建service

vim nginx-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:        #spec.selector:用于定义如何选择 pod
    app: nginx
  ports:           #spec.ports:用于定义如何暴露端口,其中,nodePort 指定可以在外部访问的端口
  - protocol: TCP
    port: 445
    targetPort: 80
    nodePort: 0
  type: NodePort
kubectl apply -f nginx-svc.yml

拆解

 ports:           #spec.ports:用于定义如何暴露端口,其中,nodePort 指定可以在外部访问的端口
  - protocol: TCP
    port: 445
    targetPort: 80
    nodePort: 30445
  type: NodePort

protocol:定义服务的类型

port:容器在集群中的运行端口

targetport:容器内部监听的端口

nodeport:表示节点上对service暴露的端口,范围是30000-32767,如果将nodeport的值改为0,则集群会自动分配可用的nodeport

type:nodeport:kubernetes service服务的一种,允许外部网络通过访问nodeIP:nodePort来访问pod,需要确保nodeport在每个节点上都可以访问

在外部网络通过nodeip:nodeport访问pod

image-20230504185436903

在集群内通过podip:podport访问pod

image-20230504185516426

通过cluster ip:端口 访问

image-20230508160308830

从容器默认端口——pod指定端口——service暴露端口过程中发生的端口映射和端口转发:以nginx服务为例

nginx默认端口号为80,在上述示例中,我们把pod中nginx在集群中运行的端口号指定为445,service中port属性是445,targetport属性设置为80,这个过程是一个端口转发的过程,在service服务中将445端口映射到了pod中容器的监听端口:80,service提供给外部访问时实际上访问的是service的445端口,最终流量被转发到了pod中容器的80端口。

重点注意事项:修改service配置后不会立刻生效,因为修改配置后service需要将配置传递给集群中的各个组件,需要一段时间才能生效

问题一:如果没有service,仅仅是在pod中指定nginx运行在集群中的端口号是445,这个过程涉及到端口映射和端口转发吗?

端口映射和端口转发要有路由流量的过程,仅仅是在pod中指定nginx运行端口是不涉及这两个过程的。

问题二:service中的port必须要和pod中指定的运行端口一致吗?

不需要,pod中指定的是容器在集群中的运行端口,但是并没有修改容器实际的运行端口,进入容器后查看,容器是运行在80端口上的,service中的port-targetport是端口转发的过程。

pod

port

tatgetPort(转发到容器实际运行的端口号)

是否生效

445

80

80

445

445

445

445

445

80

445

345

80

part5 集群中的持久化策略

5.1 持久化策略使用场景

在kubernetes集群中,需要使用持久化存储来存储应用程序数据,以确保数据的持久性、数据的安全性、数据的备份和恢复能力,以及支持应用程序的水平伸缩等特性。以下是一些使用持久化存储的场景:

  1. 数据库服务:关系型数据库、非关系型数据库等持久化存储来存储数据。

  2. 文件存储:文件上传、文件分享等场景需要持久化存储。

  3. 日志存储:应用程序日志、系统日志等需要持久化存储。

  4. 缓存存储:分布式缓存、key-value存储等需要持久化存储。

  5. 大数据存储:Hadoop、Spark、Hive等需要持久化存储来存储数据。

    ......

需要对数据进行存储和保护的应用场景,都需要使用持久化存储来存储数据。

常见的用到持久化存储的例子:部署一个运行状态不断更新的应用程序,例如一个社交媒体应用。需要持久化存储来保存应用程序的数据,以确保在应用程序更新或重启时不会丢失用户数据。

5.2 持久化存储的类型

  1. HostPath:将主机上的某个目录作为卷挂载到容器中。该策略简单易用,但是不适用于多节点的集群环境,也没有办法动态地扩展存储容量。

  2. EmptyDir:在容器所在的节点上创建一个临时的目录,并将其挂载到容器中。该策略适用于需要在容器中进行短暂的数据共享或缓存的场景,但是如果节点故障或容器重启,数据会丢失。

  3. NFS:使用 NFS 协议挂载远程的 NFS 服务器上的文件系统。该策略适用于需要共享数据或进行读写操作的场景,但是需要考虑网络延迟和 NFS 服务器的负载问题。

  4. iSCSI:使用 iSCSI 协议挂载远程的 iSCSI 存储设备上的块设备。该策略适用于需要进行高速读写的场景,但是需要考虑网络延迟和存储设备的负载问题。

  5. Ceph:使用 Ceph 存储集群提供的块存储、对象存储或文件存储服务。该策略适用于需要进行高速读写、强一致性或高可用性的场景,但是需要部署和维护 Ceph 存储集群。

  6. GlusterFS:使用 GlusterFS 分布式文件系统提供的文件存储服务。该策略适用于需要进行高速读写和高可用性的场景,但是需要部署和维护 GlusterFS 集群。

  7. Local Storage:使用本地的块设备或文件系统提供持久化存储。该策略适用于需要高速读写和低延迟的场景,但是需要考虑数据的可靠性和容量扩展的问题。

  8. External Storage:使用外部的存储系统,如 AWS EBS、Azure Disk、GCE PD 等提供持久化存储。该策略适用于需要跨云厂商或跨数据中心进行存储的场景,但是需要考虑性能、可靠性和成本的问题。

5.3 nfs、PV和PVC

集群中可以采用nfs持久化策略或者使用pv和pvc定义持久化策略类型,也可以将nfs作为pv和pvc持久化策略的一种。

nfs持久化策略:NFS是一种基于TCP/IP传输的网络文件系统协议,通过NFS协议,客户机可以像访问本地目录一样访问远程NFS服务器中的共享资源。使用nfs作为持久化存储时,是将本地服务器作为nfs服务器,在pod中直接挂载nfs存储,这种方法只适用于简单的使用场景。

使用nfs持久化存储,必须要保证nfs服务器和所有node节点上都部署了nfs服务,否则无法进行挂载

pv、pvc

在kubernetes中,对存储资源的管理方式和计算资源(cpu/内存)截然不i同,为了能够屏蔽底层存储实现的细节,让用户方便使用及管理员方便管理,kubernetes从1.0版本引入PV和PVC

pv和pvc的定义并不是针对某一种特定的持久化策略类型,而是用于描述如何使用底层存储资源,这些存储资源可以包括各种类型的持久化存储,参考4.2 持久化存储的类型,pv和pvc的作用是将应用程序和底层存储资源解耦,使得应用程序无需了解底层存储资源的细节,同时也使得管理员可以对底层存储资源进行灵活的管理和调度,具体的持久化策略类型需要根据实际情况进行选择和配置。

pv:persistentvolume(持久卷)是对存储资源的抽象,将存储定义为一种容器应用可以使用的资源,pv由管理员创建和配置,它与存储提供商的具体实现直接相关。

pvc:persistent volume claim是用户对存储资源的一个申请,就像pod消耗node的资源一样,pvc消耗pv的资源,pvc定义了pod需要的存储资源的大小和访问模式(readwriteonce、readonlymany)。

storageclass:使用pvc申请的存储空间仍然不满足应用对存储设备的各种需求,在很多情况下,应用程序对存储设备的特性和性能都有不同的要求,包括读写速度、并发性能、数据冗余等要求,kubernetes从1.4版本开始引入一个新的资源对象storageclass,用于标记存储资源和性能,根据pvc的需求动态供给合适的pv资源。

当用户创建一个 Pod 并指定需要使用持久化存储时,可以在 Pod 的配置中定义一个或多个 PVC。然后,Kubernetes 将根据 PVC 的定义自动查找或创建与之匹配的持久化存储资源,并将其绑定到 Pod 中,使 Pod 能够使用该持久化存储。

在k8s中,pv和pvc的使用可以确保应用程序数据的持久化,并且在pod重新调度或者节点故障时,数据不会丢失,同时,pv和pvc还可以提供动态的存储卷管理和多租户存储隔离等功能,使得存储资源的管理变得更加简单和灵活。

5.4 使用nfs持久化存储方式在集群中部署mysql

k8s集群中部署mysql可以不采用持久卷策略,但是不建议, 采用持久化策略,即使在容器重启或者容器迁移的情况下,数据也不会丢失。而如果不使用持久卷,容器中存储的数据只会保存在容器的文件系统中,容器重启或者迁移的时候,数据会丢失。

如果是开发或者是测试环境,可以不适用持久化策略,但是要注意数据备份。

选择一个节点当作nfs服务器,创建nfs共享文件夹

其它节点也需要安装nfs

yum install -y nfs-utils rpcbind 
mkdir -p /data
chmod 777 /data  #更改权限
mkdir /data/nfs
vim /etc/exports
/data/nfs *(rw,no_root_squash)
systemctl start rpcbind
systemctl start nfs      #启动服务
systemctl enable rpcbind
systemctl enable nfs     #设置开机自启
exportfs
showmount -e ip

image-20230426144027540

创建pv

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.16.159
    path: /data/nfs

创建pvc

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  volumeName: mysql-pv

一个集群中可以有多个pv和pvc方案,那pv和pvc是如何绑定的?

1.pvc中使用volumeName

2.通过存储类、访问模式和其他匹配条件来实现,即spec模块中的内容

pvc访问模式:

accessModes:
    - ReadWriteMany

ReadWriteOnce(RWO):可读写一次,只能被单个 Pod 挂载为读写模式。

ReadOnlyMany(ROX):只读,可以被多个 Pod 挂载为只读模式。

ReadWriteMany(RWX):可读写多次,可以被多个 Pod 挂载为读写模式

创建mysql deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: default
  labels:
    app: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
            - name: mysql-logs
              mountPath: /var/log/mysql
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "root"
      volumes:
        - name: mysql-data
          persistentVolumeClaim:
            claimName: mysql-pvc
        - name: mysql-logs
          hostPath:
            path: /data/mysql/logs

mysql配置文件pv、pvc、deployment之间的联系

pv:定义了一个名为mysql-pv的持久卷,具有10G容量,该持久卷使用NFS存储后端,定义了NFS服务器ip地址和挂载路径。

pvc:定义了一个名为mysql-pvc的持久卷生命,请求10G的存储容量。

一般情况下,PVC中的requests.storage和PV中的capacity.storage的数值应该相等或者PVC的请求不应超过PV的容量。

dep:dep的volume部分指定了两个卷的挂载,一个是mysql-data,它与之前定义的mysql-pvc持久卷声明关联,另一个是mysql-logs,使用了hostpath类型的卷,挂载路径为/data/mysql/logs,这将直接映射到宿主机上的目录,用于存储mysql的日志文件。

将 mysql.yaml 配置文件上传至虚拟机的 /root 目录下,在 /root 目录下执行命令

kubectl create -f mysql.yaml

相关实验:

使用node1节点作为nfs服务器,在node2节点上添加标签,在mysql的deployment配置文件里使用节点选择器将pod调度到node2节点上。

1.进入mysql的pod,创建数据库和表后删除deployment(因为没有专门的mysql的pod配置文件,pod是使用deployment生成的,所以删除deployment也就删除了pod)后重新使用kubectl apply -f将deployment重新部署到集群中,进入新生成的pod中的mysql容器查看数据库和表,还存在。

2.nfs服务器中共享文件夹内容和pod所在的node2节点上的hostpath所挂载的卷的内容

image-20230601142242065

image-20230601142343287

编写一个提供对外访问的service mysql-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    name: mysql
spec:
  type: NodePort
  ports:
    - port: 3306
      targetPort: 3306
      nodePort: 30003
  selector:
    app: mysql

将 mysql-svc.yaml 配置文件上传至虚拟机的 /root 目录下,在 /root 目录下执行命令

kubectl create -f mysql-svc.yaml

访问数据库并验证其运行正常

kubectl get pod

image-20230426144243931

kubectl exec -it mysql-64d9f758ff-9lcds -- mysql -u root -p

image-20230426144342562

mysql开放远程连接

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
flush privileges;        #刷新权限表,使配置生效

如果配置的是mysql8.0

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
CREATE USER 'lqy'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT ALL PRIVILEGES ON mysql.* TO 'liqy'@'%'; ##授权以及开放远程连接
flush privileges;        #刷新权限表,使配置生效

使用mysql可视化工具管理数据库

image-20230523103411029

集群中的负载均衡实验

什么是负载均衡?

负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其它服务的性能和可靠性。

此处可参考

nginx配置负载均衡:https://p12sk03vh3f.feishu.cn/file/YFW0bhiCIozXqaxb7lCcjDc7n0b

没有负载均衡

image-20230517090409208

引入负载均衡

image-20230517090727368

集群中的负载均衡

首先,我们在集群中创建一个pod,pod中包含一个nginx容器,然后创建一个deployment管理该pod并创建三个副本,随后通过配置service将pod暴露在外部网络上,通过客户端访问pod中的nginx,此时,集群中有一个我们创建pod时创建的nginx,有三个创建deployment时生成的三个nginx副本,那么我们通过客户端访问nginx时,访问到的是哪个nginx呢?

我们先分清楚集群中的几个ip:

masterIP:主节点ip

nodeIP:工作节点ip

这两个都是服务器的ip

podIP:pod的ip是由flannel分配的

image-20230516110843748

flannel是怎么给docker分配ip的

ifconfig查看flannel网络配置

image-20230516112434430

10.244是默认网段,生产环境下可以改成其它网段

CLUSTER-IP:clusterIP是k8s集群内分给集群内部使用的SVC的IP,一般用来集群内进行负载均衡

image-20230516113217314

当通过客户端访问集群中的nginx时,kubernetes的负载均衡会将请求随机分发到pod中的一个实例。

过程:每个节点都运行着一个网络代理kube-proxy,负责为service实现一种VIP的形式,外界通过service访问pod,service接收到请求通过kube-proxy转发到pod上,kube-proxy服务负责将访问service的TCP/UDP数据流转发到后端的容器,当有多个实例时,kube-proxy负责负载均衡。

kubernetes的组件

Kubernetes 的组件

control plane

控制平面组件,负责为集群做出全局决策,一般在管理节点运行

kube-apiserver:API服务器是kubernetes控制平面的组件,提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等。

image-20230517092321947

kube-scheduler:image-20230517092455234c-m:控制平面组件,负责运行控制器进程

从逻辑上讲,每个控制器都是一个单独的进程,但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。

etcd:高可用的键值对的分布式安全存储系统,用于持久化存储集群中所有的资源对象。

c-c-m:云控制平台,和云服务商进行交互

node组件

负责维护运行的pod并提供kubernetes运行环境,在node节点运行

kubelet:在集群中每个节点上运行,确保容器运行在pod中

kube-proxy:集群中每个节点上所运行的网络代理

负载均衡实验

在客户端通过主节点ip访问nginx服务,连续访问n次,通过日志工具查看到n次访问被分布到不同的nginx副本上

image-20230517110251678

kubectl get pod |grep "nginx"
kubectl log nginx-deployment-797c9c8489-2rc7h nginx

image-20230517111351288

part6 在集群中部署java项目

6.1. 创建springboot项目

6.2. 将springboot项目打包成jar包

image-20230518154943741

6.3. 在linux服务器上

Dockerfile文件

FROM openjdk:8-jdk-alpine
VOLUME /tmp

ADD helloword-0.0.1-SNAPSHOT.jar helloword-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/helloword-0.0.1-SNAPSHOT.jar", "&"]

EXPOSE 8080

6.4. 打包成镜像

docker build -t hello-java:1.0 .

image-20230518153327878

运行镜像,检测是否成功将jar包打包成镜像

docker images hello-java
docket run 54e610d6496d

image-20230518153428507

image-20230518153509438

开通阿里云容器镜像仓库

aliyun.com

搜索容器镜像服务

image-20230518153606199

创建镜像仓库

image-20230518153708445

点击创建的镜像仓库

image-20230518153748768

在linux服务器上登录--密码是开通容器镜像仓库时创建的

docker login --username=aliyunxxxxx registry.cn-xxx.aliyuncs.com   #登陆你自己的

将上一步打包的本地镜像打包成符合阿里云容器镜像仓库的镜像

docker tag 54e610d6496d registry.cn-hangzhou.aliyuncs.com/ikko/hello-java:1.0#ikko:你的命名空间 hello-java:要创建的容器名 1.0:容器版本
docker images registry.cn-hangzhou.aliyuncs.com/ikko/hello-java

image-20230518154052647

将打包好的镜像推送到阿里云镜像仓库

docker push registry.cn-hangzhou.aliyuncs.com/ikko/hello-java:1.0

image-20230518154259633

镜像仓库里查询

image-20230518154339878

6.5.集群中编写deployment

注意:如果你的阿里云容器镜像仓库设置的是私有

执行

kubectl create secret docker-registry registry-demo --namespace=default --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=aliyun2201431391 --docker-password=fsnowygP29 --docker-email=58xx11796@qq.com #自己改改
kubectl create deployment java-hello --image=registry.cn-hangzhou.aliyuncs.com/ikko/hello-java:1.0 --dry-run -o yaml > hello-java.yam

编写deployment

vim hello-java.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: ingress-nginx
  creationTimestamp: null
  labels:
    app: hello-java
  name: hello-java
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-java
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: hello-java
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/ikko/hello-java:1.0
        name: hello-java
        resources: {}
      imagePullSecrets:
        - name: registry-demo
status: {}

部署到集群中

kubectl apply  -f hello-java.yaml

查看pod

6.6. 编写service,将服务暴露出来,通过客户端访问应用

vim hello-java-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello-java-service
spec:
  selector:
    app: hello-java
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
      nodePort: 30002
  type: NodePort

部署到集群中

在客户端通过节点ip:nodeport访问

image-20230518155541780

注意

如果在阿里云容器镜像服务中设置的容器是私有,要在deployment文件中配置

imagePullSecrets:
        - name: registry-demo

数据库

配置了数据库的java项目源码

https://ikko.oss-cn-hangzhou.aliyuncs.com/helloword.zip

基本流程

安装mysql

创建数据库、表

创建用户、授权、开放远程连接

在java项目的jdbc连接池里连接数据库

如果数据库无法连接,检查pom里的依赖、检查驱动、查看报错信息

image-20230519113733959

ingress controller

使用的是

vim deploy.yaml

deploy的配置文件内容https://ikko.oss-cn-hangzhou.aliyuncs.com/deploy.txt

注意事项

·配置文件中没有default-http-backend需要在ingress中自定义

·配置文件中使用的网络策略是NodePort因为没有云服务商提供的负载均衡环境

关于ingress

·公开从集群外部到集群内部服务的http和https路由以及定义规则

·为service提供外部可访问的URL、负载均衡流量等

·将http和https以外的服务公开到internet时,通常使用service.type=nodeport或者service.type=loadbalancer类型的service

关于LoadBalancer

来自外部负载均衡器的流量将直接重定向到后端pod上,这个工作依赖于云提供商。

kubectl apply -f deploy.yaml
kubectl get services -n ingress-nginx

image-20230523090320664

创建一个为hello-java-service提供服务的ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: ingress-nginx
  name: hello-java-ingress
spec:
  ingressClassName: nginx
  defaultBackend:
    service:
      name: hello-java-service
      port:
        number: 8080
  rules:
    - host: k8s.lifesiall.top
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: hello-java-service
                port:
                  number: 8080

image-20230523094518877

image-20230523093809453

注意事项

·一组pod、deployment、svc、ingress要在同一个命名空间,命名空间可以在配置文件里用namespace定义,也可以在命令行使用-n namespace定义

·因为deploy.yaml里没有定义default-http-backend,需要在ingress配置文件里自定义

·由于本地没有LoadBalance环境,所以使用NodePort类型的service暴露服务时,ingress里配置的域名在访问时需要使用域名:NodePort访问

cadvisor

资源监控

部署

DaemonSet

DaemonSet可以在集群中每个节点都部署应用,并且如果有新的节点加入集群,也可以在新节点上自动部署

vim cadvisor.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: cadvisor
spec:
  selector:
    matchLabels:
      app: cAdvisor
  template:
    metadata:
      labels:
        app: cAdvisor
    spec:
      tolerations:   
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
      hostNetwork: true    
      restartPolicy: Always 
      containers:
      - name: cadvisor
        image: lagoudocker/cadvisor:v0.37.0
        imagePullPolicy: IfNotPresent  
        ports:
        - containerPort: 8080
        volumeMounts:
          - name: root
            mountPath: /rootfs
          - name: run
            mountPath: /var/run
          - name: sys
            mountPath: /sys
          - name: docker
            mountPath: /var/lib/containerd
      volumes:
      - name: root
        hostPath:
          path: /
      - name: run
        hostPath:
          path: /var/run
      - name: sys
        hostPath:
          path: /sys
      - name: docker
        hostPath:
          path: /var/lib/containerd
kubectl create -f cadvisor.yaml

创建service,方便管理

apiVersion: v1
kind: Service
metadata:
  name: cadvisor
  labels:
    name: cadvisor
spec:
  type: NodePort
  ports:
    - port: 8080
      targetPort: 8080
      nodePort: 30004
  selector:
    app: cadvisor

关于资源:

使用ip:port访问cadvisor,打开的是每个节点上的资源监控,因为集群内pod是被调度到节点上运行的,所以虽然pod是集群的资源,但是每个节点上运行的pod不同,所占用的资源就不同

比如当前集群pod

kubectl get pod -o wide

image-20230523143727859

可以看出nginx实在node02节点上运行的,此时查看节点资源使用情况

kubectl describe node

master

image-20230523143942577

node01

image-20230523144100604

可以明显看到节点master和node01资源占用情况不同,所以可以理解为什么每个节点都要安装cadvisor,而不是和其它类型的插件一样只需要在集群内部署一个资源。集群是运行在多个节点上的

回到cadvisor

首先分析配置文件

  spec:
      tolerations:   
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
      hostNetwork: true    
      restartPolicy: Always 

tolerations:

虽然之前没写,但是我们是可以指定pod所运行的节点的,对于没有指定的节点集群中的调度器scheduler会选择适合的节点运行pod,但是调度器将pod调度到某个节点后,并不意味着pod一定一直运行在这个节点,要看调度策略。

并且,一般pod是默认不运行在master节点的,master节点通常运行的是控制组件,并不进行普通的用户工作负载,所以配置文件中的

tolerations是一种调度策略,允许pod运行在master节点

hostnetwork:ture是一种网络策略,它允许客户端通过节点ip:端口访问服务,如果把这行注释掉,也可以通过service暴露出来

restartPolicy: Always是一种重启策略,意思是无论容器因何原因退出,都会自动重启到运行状态


volumeMounts:
          - name: root
            mountPath: /rootfs
          - name: run
            mountPath: /var/run
          - name: sys
            mountPath: /sys
          - name: docker
            mountPath: /var/lib/containerd

volumeMounts:定义了容器内部的挂载路径和宿主机上对应的挂载路径

volume:定义了宿主机上的挂载路径和它们对应的卷的名称

/rootfs:容器的根文件系统,通过将宿主机的跟文件系统挂载到容器中,cAdvisor可以获取容器所在节点的文件系统信息,例如文件大小、使用量等。

/var/run:在宿主机上,/var/run目录通常包含运行时的进程信息和套接字文件,将宿主机的/var/run目录挂载到容器中,cadvisor可以访问容器所在节点的运行时信息,例如运行的进程和套接字文件。

/sys/:/sys目录是linux内核的虚拟文件系统,提供了与内核和硬件相关的信息,通过将宿主机的/sys目录挂载到容器中,cadvisor可以获取与容器所在节点相关的系统和硬件信息,如cpu、内存、磁盘等。

/var/lib/containerd:容器运行时的数据目录,通过将宿主机的容器运行时数据目录挂载到容器中,cadvisor可以获取与容器运行时相关的信息,如容器的状态、镜像信息、容器存储等。

关于cadvisor页面信息:

image-20230523154029207

cgroup:linux操作系统中的概念,用于对进程进行资源限制和管理,在集群中,kubernetes使用cgroup来管理容器的资源限制和隔离

image-20230523164028865

查看容器的cgroup:

集群中:

kubectl get pod -o wide #查看pod运行节点
docker ps -a #在pod运行节点上获取docker id
docker inspect aa143a2cc2f6 #查看容器信息

image-20230523165016524

cadvisor中:

Docker Containers——选择容器

image-20230523165102743

查看GPU利用率,需要先安装显卡驱动,

使用ssh ip:端口登录到集群上容器内

docker拉取容器

进入容器修改密码获取hostkey安装ssh服务 --可能需要特权模式

cat /etc/ssh/sshd_config #配置文件开启22端口

编写脚本,启动sshd服务

#!/bin/bash /usr/sbin/sshd -D &

修改密码 passwd

退出容器,将容器重新打包成镜像推送到阿里云容器镜像仓库

编写pod

apiVersion: v1
kind: Pod
metadata:
  name: centos-ssh
spec:
  tolerations:
    - effect: NoSchedule
      key: node-role.kubernetes.io/master
  containers:
  - name: centos-ssh
    image: registry.cn-hangzhou.aliyuncs.com/ikko/centos-ssh:1.0
    ports:
    - containerPort: 22
    securityContext:
      capabilities:
        add: ["SYS_PTRACE", "NET_ADMIN"]
    command:
    - /bin/sh
    - -c
    - |
      /usr/sbin/sshd -D &
      sleep infinity

编写service

[root@k8s ~]# cat centos-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: centos-ssh
spec:
  selector:
    app: centos-ssh
  ports:
  - name: ssh
    protocol: TCP
    port: 22
    targetPort: 22
  type: NodePort

使用ssh访问到容器内

监控gpu资源

宿主机安装显卡驱动

安装cuda

安装nvidia-smi

安装nvidia-container-runtime,并设置为docker的默认容器运行时

运行容器,将gpu分配给容器

docker run -d --name mycontainer2 --gpus all -p 2222:22 pytorch-ssh1 tail -f /dev/null

进入容器,查看gpu资源

nvidia-smi
文章作者: Administrator
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 IKKO
linux k8s docker
喜欢就支持一下吧