0%

k8s入门

k8s入门

前置知识

1.私有网络VPC

​ 在集群内通过设置VPC来进行私有网络(专有网络)配置。

VPC.png

集群内的机器通过私有IP进行访问,这样不需要走公网IP的流量,访问时也不会因为公网的带宽限制。一般云服务器都会默认分配对应的专有网络,也可以自己配置专有网络。

若自己配置专有网络,需要配置IP网段,这个网段标志着这个专有网络最多能容纳多少台服务器。

比如配置的网段是:192.168.0.1/16(192.168.0.0 ~ 192.168.255.255)其中头尾IP被占用,剩下的IP就可以分配给对应的服务器,之后就可以通过私有网络进行访问。

在一些云产商,在配置了专用VPC之后,还可以配置交换机。再一级的细分网段。

所以比如这时可以加两个交换机(192.168.0.1/24)(192.168.10.1/24)。

如果创建了多个VPC,VPC与VPC之间是相互隔离的,相互VPC之下的机器是无法互通。

基本概念

  • Pod:是K8s调度的基本单位,一个Pod中支持多个容器,其中多个容器共享网络和文件系统,可以通过进程通信和文件共享这种简单高效的方式组合完成服务。每个Pod都有一个特殊的根容器Pause容器,以及一个或多个的业务容器组成。Pause容器作为根容器,以它的状态来代表这个Pod的运行状态,每个Pod都分配了一个唯一的IP地址(Pod IP)。Pod内的所有业务容器都共享根容器的Ip,以及共享根容器挂载的Volume
  • Node:是Pod真正运行的主机,可以是物理机也可以是虚拟机,为了更好的管理Pod,在每个Node节点上至少要容器引擎(docker)、kubeletkubelet-proxy服务。
  • Namespace:命名空间,是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或者用户组。
  • Label:是k8s对象的标签,以键值的方式附加到各种资源上,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源上,k8s通过Label Selector(标签选择器)来查询和筛选某些Label资源对象。
  • Service:是一个服务的访问入口,通过标签选择器Label SelectorPod副本集群之间进行对接,定义了一组的Pod访问策略(iptable),防止Pod失联。在创建Service时会自动为它分配一个虚拟的IP地址,即Cluster IP,服务发现就是通过ServiceNameClusterIP地址做了一个DNS域名映射来解决。
  • RepllcaSet(RC):用来确保预期的Pod副本数量,如果有过多的Pod副本运行,则会停止一些,反之则再启动一些。一般很少主动操作RC,都是通过Deployment这个更高层次的资源对象使用,从而形成一整套Pod创建、删除、更新的编排机制。
  • Deployment:用于部署无状态应用,只需要在Deployment上描述想要的目标状态,它就会将PodRC的实际状态改变到目标状态。

架构组件

k8s.png

k8s主要由以下核心组件组成:k8s集群中分为master主节点和node工作节点。

在主节点中:(控制平面)

  • kube-apiserver:提供了资源操作的唯一入口,各组件的协调者,以Http Rest方式提供接口服务,所有对象资源的增、删、改、查和监听都交给它处理后再提交到etcd中存储。
  • etcd:键值数据库,保存了整个集群的一些信息。比如PodService等对象信息。
  • kube-scheduler:调度器,根据调度算法为新创建的Pod选择一个node工作节点,可以任意部署,可以部署在同一个工作节点上,也可以部署在不同的工作节点上。
  • kube-controller-manager:是所有资源对象的自动化控制中心,一个资源对应一个控制器,而它就是负责管理这些控制器。比如有:
    • 节点控制器
    • 任务控制器
    • 端点控制器
    • 副本控制器
    • 服务账户与令牌控制器

在工作节点中:

  • kubelet:它是master主节点在node工作节点上的agent(代理),主节点通过它来管理当前工作节点的运行容器的生命周期,负责Pod对应容器的创建、启停等,实现集群管理的基本功能。
  • kube-proxy:在工作节点上实现Pod网络代理,实现kubernets Service的通信,维护网络规则和四层负责均衡工作。
  • docker engine:容器引擎,负责本机的容器创建和管理工作。

部署k8s

环境部署前遇到的一些问题

  • 由于需要使用到yum来下载一些包,但是yum需要访问镜像仓库,始终无法访问到 mirrorlist.centos.org,所以需要更换为国内的的一些镜像源。
1
2
3
4
5
6
7
8
9
10
# centos7的镜像源文件的目录
cd /etc/yum.repos.d/

# /etc/yum.repos.d/CentOS-Base.repo
# 将原本的CentOS-Base.repo备份后
# 使用阿里云镜像站,如果能使用wget,则直接下载,如果不能,可以先下载文件后贴进去
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

# 使用网易镜像站
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo

添加安装docker镜像源,这个命令执行之后,会在/etc/yum.repos.d目录下生成docker-ce.repo文件。是专门针对docker的软件包镜像源。

1
2
3
sudo yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安装docker,安装docker要注意需要和k8s版本匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
yum -y install docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io

# 启动docker
systemctl start docker

# 查看docker是否安装成功
docker version

# 配置加速镜像源
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://gr4yxx0x.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

# 查看是否成功
docker info

接着就可以开始安装K8S

  • 设置hostname,每台服务器的主机名不可重复。
1
2
3
4
5
6
7
8
9
# 查看主机名
hostname

# 设置主机名
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-node-1

# 更新
bash
  • 关闭交互区,一些安全配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看 交换分区
free -m

# 将 SELinux 设置为 permissive 模式(相当于将其禁用) 第一行是临时禁用,第二行是永久禁用
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# 关闭swap;第一行是临时禁用,第二行是永久禁用
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 允许 iptables 检查桥接流量 (K8s 官方要求)
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

# 让配置生效
sysctl --system
  • 安装k8s三大件(kubeletkubeadmkubectl)版本使用1.20.9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置k8s的yum源
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
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 install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes

# 启动kubelet
systemctl enable --now kubelet

# 查看 kubelet 状态:一会停止 一会运行。 这个状态是对的,kubelet 等待 kubeadm 发号指令。
systemctl status kubelet

k8s组件中,除了kubelet,其他组件都是通过容器的方式下载运行。

  • 安装其他组件的容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置镜像,生成 images.sh
# 逻辑上只需要在master节点上下载所有的容器镜像,在work节点上只需要下载kube-proxy
sudo tee ./images.sh <<-'EOF'
#!/bin/bash
images=(
kube-apiserver:v1.20.9
kube-proxy:v1.20.9
kube-controller-manager:v1.20.9
kube-scheduler:v1.20.9
coredns:1.7.0
etcd:3.4.13-0
pause:3.2
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/$imageName
done
EOF

# 拉取镜像
chmod +x ./images.sh && ./images.sh
  • 初始化主节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 这个要在每个节点上都配置对主节点的本地路由映射
echo "10.211.55.15 cluster-endpoint" >> /etc/hosts


# 主节点初始化 (只在 master 服务器执行, 其他 node 不用)
# --apiserver-advertise-address: master 的 IP
# --control-plane-endpoint: master 的域名
# --image-repository docker镜像仓库
# --service-cidr 和 --pod-network-cidr 是网络范围,建议不要改。要改的话 2 个cidr 和 vps(172.31.x.x) 的,3 个网络互相不能重叠;还要修改 calico.yaml的 IP(下图有写)。
kubeadm init \
--apiserver-advertise-address=10.211.55.15 \
--control-plane-endpoint=cluster-endpoint \
--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
--kubernetes-version v1.20.9 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=192.168.0.0/16

如果使用的是云服务器要注意,至少要允许在2c的服务器上。

安装成功后会得到以下提示信息,需要根据以下信息进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

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/

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

kubeadm join cluster-endpoint:6443 --token xh1xft.8m76emhyhdjr7i0o \
--discovery-token-ca-cert-hash sha256:4985192332d76a8ebead16baed30db9c43d1efdd8c26d328691005da8649d31c \
--control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join cluster-endpoint:6443 --token xh1xft.8m76emhyhdjr7i0o \
--discovery-token-ca-cert-hash sha256:4985192332d76a8ebead16baed30db9c43d1efdd8c26d328691005da8649d31c
  • 这时通过kubectl get nodes可以看到当前的节点状态,但是此时的主节点状态还是NotReady,是因为还需要下载一个网络组件。
1
2
3
4
5
6
7
# 使用calico网络组件,在主节点下载 calico.yaml
curl https://docs.projectcalico.org/manifests/calico.yaml -O

curl https://docs.projectcalico.org/v3.20/manifests/calico.yaml -O

# 加载配置
kubectl apply -f calico.yaml

这里有一个问题:我使用的是阿里云的镜像加速器,但是好像一直无法下载calico镜像。所以只能通过一些非常规手段下载。创建calico.sh,之后chmod +x calico.sh && ./calico.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# https://github.com/projectcalico/calico/releases/tag/v3.20.6 通过这个地址下载release-v3.20.6.tgz包,然后上传到服务器中。


# 然后创建cailco.sh

# !/bin/bash

# 解压
tar -zxvf release-v3.20.6.tgz

cd release-v3.20.6
cd images

# 循环加载 image
sudo tee load-images.sh <<-'EOF'
#!/bin/bash
tars=(
calico-kube-controllers.tar
calico-node.tar
calico-typha.tar
calico-cni.tar
calico-pod2daemon-flexvol.tar
)
for tar in ${tars[@]} ; do
docker load < $tar
done
EOF

chmod +x load-images.sh && ./load-images.sh

同时需要修改下载的calico.yaml中的镜像地址。(注意:如果是通过这种方式,则工作节点也需要同样操作,因为工作节点也需要这个镜像。)

1
2
3
# 原本 calico.yaml 中所规定的 image 资源都是长这样的 docker.io/calico/cni:v3.20.6, 由于这个 docker.io/ 前缀会导致 k8s 去 DockerHub 上找 image (前面已解释了走不了阿里加速器的原因),而不是使用刚才我们导入进本地的 images。所以我们用 sed -i 来全局查找替换,去掉它们。

sed -i 's/image: docker.io\//image: /g' calico.yaml
  • 工作节点运行命令,使得工作节点加入集群
1
2
3
4
kubeadm join cluster-endpoint:6443 --token xh1xft.8m76emhyhdjr7i0o \
--discovery-token-ca-cert-hash sha256:4985192332d76a8ebead16baed30db9c43d1efdd8c26d328691005da8649d31c

# 如果使用虚拟机部署,要注意服务器之间的防火墙有没有关闭,可能出现无法访问的情况。

加入集群的令牌的有效期是24小时,重新获取令牌。

1
2
# 重新获取令牌
kubeadm token create --print-join-command

在k8s中一般都是通过.yaml来进行一些操作。

1
2
kubectl apply -f xxx.yaml
kubectl delete -f xxx.yaml

我在测试时候使用的是云服务器,后面转到虚拟机上,部署了同样的环境。(不行,这个修改方式有问题,虽然乍一看修改之后是没有什么问题,通过kubectl get nodes查看的状态也是对的,但是我在创建pod的时候一直创建不起来,甚至连pod都没有去创建,也不知道是因为什么,通过systemctl status kubelet查看日志,其中有打印出还是通过旧的地址访问serverapi接口,说明哪里改漏了,没有改到,但是具体哪里就不知道了。)

1
2
3
4
5
6
7
8
# 但是由于我部署的时候是和我后面用的时候不是同一个wifi网络环境,导致我在重启虚拟机之后ip变了。
# 重启虚拟机之后要先启动docker,再启动k8s
systemctl start docker
systemctl enable --now kubelet

cd /etc/kubernetes/manifests
vi etcd.yaml
vi kube-apiserver.yaml

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看 k8s 集群 所有节点
kubectl get nodex

# 查看命名空间
kubectl get ns

# 查看 k8s 集群 部署了 哪些应用运行的应用在 docker 中叫 container(容器),在 k8s 中叫 pod
kubectl get pods -A对应 docker 中 的docker ps

# 查看 默认命名空间(default)部署的应用
kubectl get pods

# 查看 完整的信息,有 部署的 节点、节点IP 等。
kubectl get pod -A -owide

# 打印 整个状态变化过程
kubectl get pod -w

namespace

1
2
3
4
5
6
7
8
# 查看 某个命名空间(kubernetes-dashboard)部署的应用
kubectl get pod -n kubernetes-dashboard

# 创建命名空间 hello
kubectl create ns hello

# 删除命名空间 hello
kubectl delete ns hello

pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建名为 mynginx-k8s 的 Pod (默认命名空间)
kubectl run mynginx-k8s --image=nginx

# 进入到 Pod 里面(和 docker exec -it 一样的)
kubectl exec -it Pod名字 -- /bin/bash

# 查看 Pod mynginx-k8s 的描述
kubectl describe pod mynginx-k8s

# 删除 在默认命名空间的 mynginx-k8s
kubectl delete pod mynginx-k8s

# 删除 在 xxx 命名空间的 mynginx-k8s
kubectl delete pod mynginx-k8s -n xxx

# 查看 Pod mynginx-k8s 的运行日志(默认的命名空间)
kubectl logs mynginx-k8s

# 查看 Pod 运行日志(-n 就是 namespace 命名空间)
kubectl logs -f -n xxx命名空间 xxxPodName

deployment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 用 Deployment 部署 Pod,deploy 名为 mytomcat,使用镜像 tomcat:8.5.68
kubectl create deployment mytomcat --image=tomcat:8.5.68

# 查看 Deployment 创建的资源
kubectl get deploy

# 删除 Deployment 创建的资源,用 delete 是删不掉的
kubectl delete deploy mytomcat

# --replicas=3,部署 3个 Pod my-dep
kubectl create deployment my-dep --image=nginx --replicas=3

# 对 Deployment my-dep 扩容 成 5 个 Pod
kubectl scale deploy/my-dep --relicas=5

# 对 Deployment my-dep 缩容 成 2 个 Pod
kubectl scale deploy/my-dep --relicas=2

# 查看之前用的镜像(spec.container.image)
kubectl get deploy/my-dep -oyaml

# 查看之前用的镜像
kubectl get deploy/my-dep -oyaml | grep image

# 改变 my-dep 中 nginx 版本(nginx 最新版 -> 1.16.1)滚动更新
kubectl set image deployment/my-dep nginx=nginx:1.16.1 --recordkubectl rollout status deployment/my-dep

# 历史记录
kubectl rollout history deployment/my-dep

# 查看 my-dep 某个历史详情
kubectl rollout histroy deployment/my-dep --revision=2

# my-dep 回滚(回到上个版本)
kubectl rollout undo deployment/my-dep

# my-dep 回滚到指定版本
kubectl rollout undo deployment/my-dep --to-revision=2

deployment中还有一些细分:

  • Deployment:无状态应用部署,比如微服务,提供多副本等功能。
  • StatefulSet:有状态应用部署,比如redis,提供稳定的存储、网络等功能
  • DeamonSet:守护型应用部署,比如日志收集组件,在每个机器都运行一份。
  • Job/CronJob:定时任务部署,比如垃圾清理组件,可以在指定时间运行。

Service

Pod的服务发现与负责均衡,将一组Pods公开为网络服务的抽象方法。如果访问是通过直接IP的方式,当其中的一个Pod或者是服务器宕了之后,就直接无法访问了,所以在k8s中,Pod的网络控制由Service管理,请求访问到Service上,由Service转到对应的Pod上,当然它也有负载均衡的能力。

Service有两种创建方式,或者说有两种创建类型

  • ClusterIP:默认的访问方式(创建的时候不写就是使用这种方式),只能集群内访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# kubectl expose 暴露端口,只能在集群内部 ClusterIP 访问。--type=ClusterIP 不传默认就是ClusterP
# target-port 目标Pod的端口(源端口)
# port service的端口
kubectl expose deploy my-dep-02 --port=8000 --target-port=80

# 在集群内通过域名访问:服务名.命名空间.svc ; 比如 my-dep-02.default.svc

# 查看 service,里面有 CLUSTER-IP
# kubectl get service 或者 kubectl get svc
kubectl get service

# 查看 pod 标签
kubectl get pod --show-labels

# 删除
kubectl delete svc my-dep-02
  • NodePort:在公网上可以访问,但是这种方式暴露的端口是随机的。这种模式可以访问每一台服务器的暴露端口,比如创建之后生成的端口是30999,那么每一台服务器的IP:30999,都能访问到,且具备负责均衡。
1
2
3
4
5
6
7
8
# 只能集群内部访问(--type不写 默认 ClusterIP)
kubectl expose deploy my-dep-02 --port=8000 --target-port=80 --type=ClusterIP

# 集群外部也可以访问
kubectl expose deploy my-dep-02 --port=8000 --target-port=80 --type=NodePort

# 查看
kubectl get svc

小Tip:使用ClusterIP类型分配的IP地址,在初始化时其实配置了IP地址的范围。下方的--service-cidr。同样的下方的--pod-network-cidr是所有的podIP范围。

1
2
3
4
5
6
7
kubeadm init \
--apiserver-advertise-address=172.31.0.2 \
--control-plane-endpoint=cluster-endpoint \
--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
--kubernetes-version v1.20.9 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=192.168.0.0/16

Ingress

它是Service的统一网关入口,底层是nginx。所有的请求都是先到ingress,由ingress来打理这些请求,类似微服务中的网关层。

k8s.png

安装ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml

# 修改镜像
vi deploy.yaml
# 将 image 的值改为如下值
registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0

# 安装资源
kubectl apply -f deploy.yaml

# 检查安装的结果
kubectl get pod,svc -n ingress-nginx

# 最后别忘记把 svc 暴露的端口 在安全组放行

删除ingress

1
2
3
4
5
6
7
8
9
10
kubectl delete -f deploy.yaml

# 不知道为啥会删不干净
kubectl get ns ingress-nginx -o json > tmp.json

# 开启本地访问
kubectl proxy

# 再开一个窗口
curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/ingress-nginx/finalize

安装之后查看安装结果,可以看到ingress-nginx-controller通过NodePort方式暴露了两个端。

31276这个是http的访问端口,31267这个是https的访问端口。

1
2
3
4
5
[root@master home]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.2.61 <none> 80:31276/TCP,443:31267/TCP 2m44s
ingress-nginx-controller-admission ClusterIP 10.96.31.252 <none> 443/TCP 2m44s

访问http://10.211.55.15:31067/出现了nginx的404页面。

这里就简单的做个ingress的测试:如果访问的是user.xiaocainiao.com那么显示”Hello World!“。如果访问的是pay.xiaocainiaoya.com那么显示的是nginx的欢迎页面。

创建两个Deployment和两个Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-server
spec:
replicas: 1
selector:
matchLabels:
app: hello-server
template:
metadata:
labels:
app: hello-server
spec:
containers:
- name: hello-server
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/hello-server
ports:
- containerPort: 9000
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
selector:
app: nginx-demo
ports:
- port: 8000
protocol: TCP
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-server
name: hello-server
spec:
selector:
app: hello-server
ports:
- port: 8000
protocol: TCP
targetPort: 9000

然后在k8s中执行:

1
2
3
vi test.yaml

kubectl apply -f test.yaml

接着创建路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "user.xiaocainiao.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000 # hello-server (service) 的端口是 8000
- host: "pay.xiaocainiaoya.com"
http:
paths:
- pathType: Prefix
path: "/" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo #java,比如使用路径重写,去掉前缀nginx
port:
number: 8000

然后在k8s中执行:

1
2
3
vi ingress-rule.yaml

kubectl apply -f ingress-rule.yaml

刚执行完命令,可能在ADDRESS一栏为空,稍微等一等之后会分配这个ingress的访问地址。

1
2
3
4
[root@master home]# kubectl get ingress -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
default ingress-host-bar nginx user.xiaocainiao.com,pay.xiaocainiaoya.com 10.211.55.16 80 12m

我是用虚拟机做测试,需要进行本机的路由代理。

1
2
10.211.55.16 user.xiaocainiao.com
10.211.55.16 pay.xiaocainiaoya.com

用这个访问地址+刚刚安装的ingress-manager暴露的端口进行访问。

ingress.png

存储挂载

k8s的场景中,pod在集群中部署的节点机是由deployment决定,假设说某一个pod挂了之后,可能deployment在识别到之后通过故障恢复,会将在其他机器上重新部署一个该pod。所以这时会存在一种情况,重新部署的pod理应能读取到之前pod故障之前写入到磁盘的一些持久性数据,所以在k8s体系中,引入了存储层框架。

k8s中可以使用的一些存储层框架:Glusterfs、NFS、CephFS。

这里以NFS为例,需要在每一台节点机上安装NFS。每个机器上安装一个NFS存储层框架,然后相互之间进行数据同步,假设某一个pod故障之后,被转移到了其他的机器上,也能通过相同的挂载目录读取到之前持久化数据。

1
2
3
4
5
6
7
8
9
10
11
12
yum install -y nfs-utils

# 然后在主节点上运行
# 只在 mster 机器执行:nfs主节点,rw 读写
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports

mkdir -p /nfs/data
systemctl enable rpcbind --now
systemctl enable nfs-server --now

# 配置生效
exportfs -r

到此就表示,在master机器上开放了/nfs/data/目录,用来做成存储空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 检查,下面的 IP 是master IP
showmount -e 192.168.27.251

# 在 2 个从服务器 执行,执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir -p /nfs/data

# 在 2 个从服务器执行,将远程 和本地的 文件夹 挂载
mount -t nfs 192.168.27.251:/nfs/data /nfs/data

# 在 master 服务器,写入一个测试文件
echo "hello nfs server" > /nfs/data/test.txt

# 在 2 个从服务器查看
cd /nfs/data
ls

原生方式 数据挂载

在 /nfs/data/nginx-pv 挂载,然后 修改, 里面 两个 Pod 也会 同步修改。

问题:①如果某个Pod不需要了,删掉Pod之后,文件还在,内容也在,②空间受机器空间管理,创建之后逻辑上是无限大的空间,除非达到机器上限,是没法管理大小的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html # 挂载目录
volumes:
# 和 volumeMounts.name 一样
- name: html
nfs:
# master IP
server: 192.168.27.251
path: /nfs/data/nginx-pv # 要提前创建好文件夹,否则挂载失败
1
2
3
4
5
6
7
8
9
10
11
cd /nfs/data
mkdir -p nginx-pv
ls

vi deploy.yaml

# 复制上面配置

kubectl apply -f deploy.yaml

kubectl get pod -owide

6.3 PV 和 PVC

PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置

PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格

静态供应:在主节点上的nfs/data/目录下创建三个文件夹,并且通过yaml文件对其进行配置。

  • 01:挂载名称为pv01-10m,且持久卷池的名称为nfs,空间为10M,多节点可读写
  • 02:挂载名称为pv02-1gi,且持久卷池的名称为nfs,空间为1G,多节点可读写
  • 03:挂载名称为pv03-3gi,且持久卷池的名称为nfs,空间为3G,多节点可读写
1
2
3
4
# 在 nfs主节点(master服务器) 执行
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m
spec:
# 限制容量
capacity:
storage: 10M
# 读写模式:可读可写
accessModes:
- ReadWriteMany
storageClassName: nfs # 表示持久卷池子的名称
nfs:
# 挂载 上面创建过的文件夹
path: /nfs/data/01
# nfs 主节点服务器的 IP
server: 192.168.27.251
---
apiVersion: v1
kind: PersistentVolume
metadata:
# 这个name 要小写,如 Gi 大写就不行
name: pv02-1gi
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/02
# nfs 主节点服务器的 IP
server: 192.168.27.251
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/03
# nfs 主节点服务器的 IP
server: 192.168.27.251
1
2
3
4
5
6
7
8
vi pv.yaml

# 复制上面文件

kubectl apply -f pv.yaml

# 查看 pv, kubectl get pv
kubectl get persistentvolume

创建、绑定 PCV

创建一个持久卷声明:从持久卷池子名为nfs的池子中申请一个至少有200M大小的空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
# 需要 200M的 PV
storage: 200Mi
# 上面 PV 写的什么 这里就写什么
storageClassName: nfs

绑定到pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-pvc
name: nginx-deploy-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deploy-pvc
template:
metadata:
labels:
app: nginx-deploy-pvc
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
# 之前是 nfs,这里用 pvc
persistentVolumeClaim:
claimName: nginx-pvc # 绑定持久卷声明

既然有静态供应那么也就会有动态供应,在静态供应商中,是创建好了一个个不同大小的PV,并把这些PV进行分组命名(池子名称),等需要使用时,通过这个分组名称(池子名称)去这个组里获取到最适合的空间大小的PV。这种方式比较麻烦的是,需要手动创建一个个PV,且空间大小上无法相对准确的预估,容易存在浪费。比如我只需要20M的空间,但是池子里的PV分别为1G,2G,3G,那么这时至少会给我1G的那个PV。

动态供应:就是可以动态的创建具体的PV,那么这种方式创建的PV的空间大小就会相对符合需要,不会造成过多的浪费。

配置集ConfigMap

k8s中部署POD,比如redis的启用,需要依赖于一些配置(配置一些服务器地址等),这时可以将这个配置内容添加到k8s的配置集中,那么所有的pod就可以都引用到这份配置文件,并且当需要修改配置时,只需要对这个配置集进行修改,POD中指定的配置文件也会相应的同步新的配置(一小段时间之后)。

假设我有配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 设置Redis监听的端口,默认为6379
port 6379

# 设置Redis监听的网络接口的IP地址
# bind 127.0.0.1

# 设置Redis是否以守护进程方式运行
daemonize no

# 设置Redis的日志文件路径
logfile "/var/log/redis/redis-server.log"

# 设置数据库的数量,默认16个数据库(0...15),可以通过select <dbid>命令选择数据库
databases 16

# 设置密码认证
# requirepass yourpassword

# 设置快照功能,即持久化
# save <seconds> <changes>
# save 900 1
# save 300 10
# save 60 10000

# 设置持久化的文件
dbfilename dump.rdb
dir /var/lib/redis

# 设置当主服务器失效时,从服务器是否仍然可读
slave-serve-stale-data yes

# 设置是否在每个命令后进行日志记录
appendonly no

# 设置更新日志的文件名
appendfilename "appendonly.aof"

# 设置更新日志写入策略
# appendfsync always
appendfsync everysec
# appendfsync no

# 设置Redis最大内存容量
# maxmemory <bytes>

# 设置内存淘汰策略
# maxmemory-policy volatile-lru
1
2
3
4
5
6
7
8
9
10
11
12
13
14
vi redis.conf
# 写
appendonly yes

# 创建配置,redis保存到k8s的etcd;
kubectl create cm redis-conf --from-file=redis.conf

# 查看
kubectl get cm

rm -rf redis.conf

# 查看 ConfigMap 的 yaml 配置咋写的
kubectl get cm redis-conf -oyaml

显示这个配置集的内容如下。(它是存储在tecd中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
data:
# key为redis.conf 值为具体的redis启动配置值
redis.conf: "# 设置Redis监听的端口,默认为6379\nport 6379\n \n# 设置Redis监听的网络接口的IP地址\n# bind 127.0.0.1\n
\n# 设置Redis是否以守护进程方式运行\ndaemonize no\n \n# 设置Redis的日志文件路径\nlogfile \"/var/log/redis/redis-server.log\"\n
\n# 设置数据库的数量,默认16个数据库(0...15),可以通过select <dbid>命令选择数据库\ndatabases 16\n \n# 设置密码认证\n#
requirepass yourpassword\n \n# 设置快照功能,即持久化\n# save <seconds> <changes>\n# save
900 1\n# save 300 10\n# save 60 10000\n \n# 设置持久化的文件\ndbfilename dump.rdb\ndir
/var/lib/redis\n \n# 设置当主服务器失效时,从服务器是否仍然可读\nslave-serve-stale-data yes\n \n# 设置是否在每个命令后进行日志记录\nappendonly
no\n \n# 设置更新日志的文件名\nappendfilename \"appendonly.aof\"\n \n# 设置更新日志写入策略\n# appendfsync
always\nappendfsync everysec\n# appendfsync no\n \n# 设置Redis最大内存容量\n# maxmemory
<bytes>\n \n# 设置内存淘汰策略\n# maxmemory-policy volatile-lru\n"
kind: ConfigMap
metadata:
creationTimestamp: "2024-07-24T16:02:55Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:redis.conf: {}
manager: kubectl-create
operation: Update
time: "2024-07-24T16:02:55Z"
name: redis-conf # 创建了一个名为redis-conf的配置集
namespace: default
resourceVersion: "14777"
uid: a626dec1-6e28-4ed0-a5ce-0aaeafffe12f

创建pod来引用这个配置集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
command:
# 启动命令 如果是直接启动redis,一般写为 redis-server /path/to/redis.conf
- redis-server
# 指的是redis容器内部的位置
- "/redis-master/redis.conf"
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /data
name: data # 引用名称是叫dada的卷
- mountPath: /redis-master # 这里表示挂载pod的这个位置
name: config # 引用名称叫config的卷
volumes:
- name: data # 创建一个名称叫data的卷
emptyDir: {}
- name: config # 创建一个名称叫config的卷
configMap: # 它是一个configMap配置集类型
name: redis-conf # 找到配置集中的这个cm
items:
- key: redis.conf # 获取到key为redis.conf的配置
path: redis.conf # 把key为redis.conf的配置的值写入到这个地址

注:配置集是具备了热更新的能力,修改了配置集中的配置值的内容,它会同步到pod中配置的制定文件上,但是如果pod中的应用想要获取到配置热更新之后的值,应用本身得拥有热更新的能力。(所以这时可能需要重启pod来读取最新的配置值)

密钥集Secret

用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod的定义或者容器镜像中来说更加安全和灵活。

1
2
3
4
5
6
7
8
9
10
11
##命令格式
kubectl create secret docker-registry regcred \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>

kubectl create secret docker-registry cgxin-docker-secret \
--docker-username=leifengyang \
--docker-password=Lfy123456 \
--docker-email=534096094@qq.com
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Pod
metadata:
name: private-cgxin-docker
spec:
containers:
- name: private-cgxin-docker
image: cgxin/cgxin_docker:1.0
# 加上 Secret
imagePullSecrets:
- name: cgxin-docker-secret # 使用密钥集Secret
-------------本文结束感谢您的阅读-------------