K8S极简教程(4小时快速学会)

1. K8S 概览

1.1 K8S 是什么

K8S官网文档:https://kubernetes.io/zh/docs/home/

1.2 K8S核心特性

  • 服务发现与负载均衡:无需修改你的应用程序即可使用陌生的服务发现机制。
  • 存储编排:自动挂载所选存储系统,包括本地存储。
  • Secret和配置管理:部署更新Secrets和应用程序的配置时不必重新构建容器镜像,且不必将软件堆栈配置中的秘密信息暴露出来。
  • 批量执行:除了服务之外,Kubernetes还可以管理你的批处理和CI工作负载,在期望时替换掉失效的容器。
  • 水平扩缩:使用一个简单的命令、一个UI或基于CPU使用情况自动对应用程序进行扩缩。
  • 自动化上线和回滚:Kubernetes会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保你不会同时终止所有实例。
  • 自动装箱:根据资源需求和其他约束自动放置容器,同时避免影响可用性。
  • 自我修复:重新启动失败的容器,在节点死亡时替换并重新调度容器,杀死不响应用户定义的健康检查的容器。

1.3 K8S 核心架构

我们已经知道了 K8S 的核心功能:自动化运维管理多个容器化程序。那么 K8S 怎么做到的呢?这里,我们从宏观架构上来学习 K8S 的设计思想。首先看下图:

K8S 是属于Master-Worker架构,即有 Master 节点负责核心的调度、管理和运维,Worker 节点则

执行用户的程序。但是在 K8S 中,主节点一般被称为Master Node ,而从节点则被称为Worker Node 或者 Node。

注意:Master Node 和 Worker Node 是分别安装了 K8S 的 Master 和 Woker 组件的实体服务器,

每个 Node 都对应了一台实体服务器(虽然 Master Node 可以和其中一个 Worker Node 安装在同

一台服务器,但是建议 Master Node 单独部署),所有 Master Node 和 Worker Node 组成了

K8S 集群,同一个集群可能存在多个 Master Node 和 Worker Node

首先来看Master Node都有哪些组件:

  • kube-apiserver。K8S 的请求入口服务。API Server 负责接收 K8S 所有请求(来自 UI 界面或者CLI命令行工具),然后,API Server 根据用户的具体请求,去通知其他组件干活。
  • Scheduler。K8S 所有 Worker Node 的调度器。当用户要部署服务时,Scheduler 会选择最合适的 Worker Node(服务器)来部署。
  • Controller Manager。K8S 所有 Worker Node 的监控器。Controller Manager 有很多具体的
    Controller,Node Controller、Service Controller、Volume Controller等。Controller 负责监控和调整在 Worker Node上部署的服务的状态,比如用户要求 A 服务部署 2个副本,那么当其中一个服务挂了的时候,Controller 会马上调整,让 Scheduler 再选择一个 Worker Node 重新部署服务。
  • etcd。K8S 的存储服务。etcd 存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server
    才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据。

接着来看Worker Node的组件:

  • Kubelet。Worker Node 的监视器,以及与 Master Node 的通讯器。Kubelet 是 Master Node
    安插在 Worker Node 上的"眼线",它会定期向 Master Node 汇报自己 Node上运行的服务的状态,并接受来自Master Node 的指示采取调整措施。负责控制所有容器的启动停止,保证节点工作正常。
  • Kube-Proxy。K8S 的网络代理。Kube-Proxy 负责 Node 在 K8S 的网络通讯、以及对外部网络流量的负载均衡。
  • Container Runtime。Worker Node 的运行环境。即安装了容器化所需的软件环境确保容器化程序能够跑起来,比如 Docker Engine运行环境

2、K8S安装教程

视频地址:图灵K8S

2.1. 安装要求

  • 3台以上机器,操作系统 CentOS7.7以上64位系统
  • 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多
  • 集群中所有机器之间网络互通
  • 可以访问外网,需要拉取镜像
  • 禁止swap分区

2.2. centos7兼容版本(7.7~7.9)

2.3. 三台主机

搭建k8s集群,三台主机,每台至少2G以上

主机 说明

主机 说明
192.168.23.201 k8s-master
192.168.23.202 k8s-node1
192.168.23.203 k8s-node2

备注:本次装机选用k8s 1.19.16版本,dokcer1.18.09版本

主机安装参考链接,这里只参考第六集

黑马k8s第六集

2.4. 安装docker(三台主机都需要安装)

powershell 复制代码
#卸载旧版本
sudo yum remove docker \
                docker-client \
                docker-client-latest \
                docker-common \
                docker-latest \
                docker-latest-logrotate \
                docker-logrotate \
                docker-engine

sudo yum update -y

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

#配置docker的yum地址
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

#安装指定docker版本
sudo yum -y install docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io


#启动dokcer并开机自启
sudo systemctl start docker
sudo systemctl enable docker


#Docker配置修改
vim /etc/docker/daemon.json

{
  "graph": "/data/docker",
  "registry-mirrors": [
  		"https://xv8xjvpp.mirror.aliyuncs.com",
        "https://docker.m.daocloud.io/",
        "https://dockerproxy.com/",
        "https://mirror.baidubce.com/",
        "https://docker.nju.edu.cn/",
        "https://ccr.ccs.tencentyun.com/"	
  ],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
#加载配置文件并重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker

常见错误

如果yum update失败,需要进行更换镜像,下面以清华镜像为例, 三台机器都要操作

  1. 打开配置yum所在文件,CentOS-Base.repo
powershell 复制代码
vi /etc/yum.repos.d/CentOS-Base.repo
  1. 将CentOS-Base.repo里的内容全部替换为以下内容
xml 复制代码
# CentOS-Base.repo   
[base]  
name=CentOS-$releasever - Base  
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/  
        http://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/os/$basearch/  
gpgcheck=1  
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7  
  
#released updates   
[updates]  
name=CentOS-$releasever - Updates  
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/  
        http://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/updates/$basearch/  
gpgcheck=1  
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7  
  
#additional packages that may be useful  
[extras]  
name=CentOS-$releasever - Extras  
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/  
        http://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/extras/$basearch/  
gpgcheck=1  
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7  
  
#additional packages that extend functionality of existing packages  
[centosplus]  
name=CentOS-$releasever - Plus  
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/  
        http://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/centosplus/$basearch/  
gpgcheck=1  
enabled=0  
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7  
  
#contrib - packages by Centos Users  
[contrib]  
name=CentOS-$releasever - Contrib  
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/  
        http://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/contrib/$basearch/  
gpgcheck=1  
enabled=0  
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7  
  
# 使用failovermethod指定优先级,这里设置为随机(roundrobin),也可以改为priority并指定每个URL的优先级  
failovermethod=roundrobin
  1. 清理YUM缓存并更新,更新完之后再安装Docker
xml 复制代码
yum clean all
yum makecache
yum update

2.5. 主机环境配置(三台都需要)

powershell 复制代码
#1.关闭防火墙
sudo systemctl stop firewalld
sudo systemctl disable firewalld

#2.关闭selinux
#selinux禁用
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config

#2.关闭swap分区
swapoff -a   
vim /etc/fstab # 注释到swap那一行  永久关闭

#3.设置主机名
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-node1
hostnamectl set-hostname k8s-node2

#4.添加host,IP需要改成你自己机器的IP
cat >> /etc/hosts << EOF
192.168.23.201 k8s-master
192.168.23.202 k8s-node1
192.168.23.203 k8s-node2
EOF

#5.允许iptables 检查桥接流量
cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

#6.设置时间同步
yum install -y ntpdate
ntpdate time.windows.com

2.6. 安装kubelet,kubeadm,kubectl(三台机器都需要执行)

powershell 复制代码
#1.配置k8s的yum源
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

#2.如果之前安装了k8s,先卸载旧版本
yum -y remove kubelet kubeadm kubectl

#3.查看可以安装的版本
 #可以将 kubelet 替换为 kubeadm 或 kubectl,以查看相应组件的可用版本
yum list --showduplicates kubelet | sort -r   

#4,安装指定的kubelet,kubeadm,kubectl版本
sudo yum install -y kubelet-1.19.16 kubeadm-1.19.16 kubectl-1.19.16

# 启动kubelet并卡机自启
sudo systemctl start kubelet
sudo systemctl enable kubelet

#检查k8s是否启动
sudo systemctl status kubelet

#排查错误
journalctl -xefu kubelet


#master主机上执行
# 下载镜像。
# 此镜像 kubernetes 的仓库中,由于网络原因,无法连接,下面提供了一种替换方案。
images=(
	kube-apiserver:v1.19.16
	kube-controller-manager:v1.19.16
	kube-scheduler:v1.19.16
	kube-proxy:v1.19.16
	pause:3.2
	etcd:3.4.13-0
	coredns:1.7.0
)

for imageName in ${images[@]};do
	docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
	docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
	docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 
done

kubeadm init \
	--apiserver-advertise-address=192.168.23.201 \
	--image-repository=registry.aliyuncs.com/google_containers \
	--kubernetes-version=v1.19.16 \
	--pod-network-cidr=192.168.0.0/16 \
	--service-cidr=10.96.0.0/12

#master主机上执行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf


#手动拉取(三台机器都要)
docker pull docker.io/calico/cni:v3.20.6
docker pull docker.io/calico/kube-controllers:v3.20.6
docker pull docker.io/calico/node:v3.20.6


#安装网络插件 Calico(仅master主机需要)
#下载calico.yaml
mkdir /root/k8s
cd /root/k8s
wget https://docs.projectcalico.org/v3.20/manifests/calico.yaml
kubectl apply -f calico.yaml


#申请一个新令牌
kubeadm token create --print-join-command

#加入node节
#复制新生成的令牌
kubeadm join 192.168.23.201:6443 --token xxxx     --discovery-token-ca-cert-hash sha256:xxxxx

三个节点都是Ready表示搭建成功

3. K8S基础命令

3.1 kubectl命令使用

使用kubectl 查看

xml 复制代码
Cluster Management Commands:
  certificate   修改 certificate 资源.
  cluster-info  显示集群信息
  top           Display Resource (CPU/Memory/Storage) usage.
  cordon        标记 node 为 unschedulable
  uncordon      标记 node 为 schedulable
  drain         Drain node in preparation for maintenance
  taint         更新一个或者多个 node 上的 taints

Troubleshooting and Debugging Commands:
  describe      显示一个指定 resource 或者 group 的 resources 详情
  logs          输出容器在 pod 中的日志
  attach        Attach 到一个运行中的 container
  exec          在一个 container 中执行一个命令
  port-forward  Forward one or more local ports to a pod
  proxy         运行一个 proxy 到 Kubernetes API server
  cp            复制 files 和 directories 到 containers 和从容器中复制 files 和 directories.
  auth          Inspect authorization

Advanced Commands:
  diff          Diff live version against would-be applied version
  apply         通过文件名或标准输入流(stdin)对资源进行配置
  patch         使用 strategic merge patch 更新一个资源的 field(s)
  replace       通过 filename 或者 stdin替换一个资源
  wait          Experimental: Wait for a specific condition on one or many resources.
  convert       在不同的 API versions 转换配置文件
  kustomize     Build a kustomization target from a directory or a remote url.

Settings Commands:
  label         更新在这个资源上的 labels
  annotate      更新一个资源的注解
  completion    Output shell completion code for the specified shell (bash or zsh)

Other Commands:
  alpha         Commands for features in alpha
  api-resources Print the supported API resources on the server
  api-versions  Print the supported API versions on the server, in the form of "group/version"
  config        修改 kubeconfig 文件
  plugin        Provides utilities for interacting with plugins.
  version       输出 client 和 server 的版本信息

3.2 Namespace

k8s中,命名空间(Namespace) 提供一种机制同一集群中的资源划分为相互隔离的组,同一命名空间内的资源名称要唯一,命名空间是用来隔离资源的,不隔离网路。

kubernetes启动时会创建四个初始命名空间:

  • default

    kubernetes包含这个命名空间,以便你无需创建新的命名空间即可开始使用新集群

  • kube-node-lease

    该命名空间包含用于各个节点关联的Lease(租约)对象。节点租约允许kubelet发送心跳,由此控制能够检测到节点故障。

  • kube-public

    所有的客户端(包括未经身份验证的客户端)都可以读取该命名空间。该命名空间主要预留未集群使用,以便某些资源需要在整个集群中可见可读。该命名空间的公属性是一种约定而非要求。

  • kube-system

    该命名空间使用kubernetes系统创建的对象。

xml 复制代码
#查看namespace
kubectl get namespace
#查看kube-system下的pod
kubectl get pods -n kube-system
#查看所有namespace下的pod
kubectl get pods -A

创建Namespace

  • 命令行方式
xml 复制代码
kubectl create namespace XXXXX
  • yaml方式

新建一个名为

my-namespace.yaml 的 YAML 文件,并写入下列内容:

xml 复制代码
#XXXXX.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace

然后运行:

xml 复制代码
kubectl create -f XXXXX.yaml

删除namespace

xml 复制代码
kubectl delete namespace XXXXX
kubectl delete -f XXXXX.yaml

3.3 Pod

创建Pod示例:运行一个NGINX容器

命令方式

yaml 复制代码
#创建pod
kubectl run mynginx --image=nginx:1.14
yaml 复制代码
#获取pod的信息,-owide 表示更详细的显示信息 -n 命名空间 查询对应namespace下的pod
kubectl get pod
kubectl get pod -owide
kubectl get pod -n <namespace-name>
yaml 复制代码
#查看pod的详情
kubctl describe pod <pod-name>


yaml 复制代码
#查看pod的运行日志
kubectl logs <pod-name>
#删除pod
kubectl delete pod <pod-name>

yaml方式

yaml 复制代码
#nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
   labels:
      run: mynginx
   name: mynginx
spec:
   containers:
   - name: nginx
     image: nginx:1.14.2
     ports:
     - containerPort: 80

部署成功访问nginx

3.4 Deployment

Deployment负责创建和更新应用程序的实例,使Pod拥有多副本,自愈,扩容等能力。创建Deployment后,kubernetes master将应用程序实列调整到集群中的各个节点上。如果托管实列的节点关闭或被删除,Deployment控制器会将该实例替换为集群中另一个节点上的实例,这提供了一种自我修复机制来解决机器故障维护问腿。

创建一个Tomcat应用程序

使用 kubectl create deployment 命令可以创建一个应用部署deployment与pod

yaml 复制代码
 #my-tomcat表示pod的名称 --image表示镜像的地址 
 kubectl create deployment my-tomcat --image=tomcat:9.0.55
 
 #查看一下deployment的信息
 kubectl get deployment
 
 #删除deployment
 kubectl delete deployment my-tomcat

 #查看Pod打印的日志
 kubectl logs my-tomcat-6d6b57c8c8-n5gm4

 #使用 exec 可以在Pod的容器中执行命令
 kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- env   #使用 env 命令查看环境变量
 kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- ls /   # 查看容器的根目录下面内容
 kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- sh   #进入Pod容器内部并执行bash命令,如果想退出
容器可以使用exit命令

思考:下面两个命令有什么区别?

yaml 复制代码
kubectl create my-tomcat --image=tomcat:9.0.55
kubectl create deployment my-tomcat --image=tomcat:9.0.55

自愈

现在我们来删除刚刚添加的pod,看看会发生什么

yaml 复制代码
 #查看pod信息,-w意思是一直等待观察pod信息的变动
 kubectl get pod -w

开另外一个命令窗口执行如下命令,同时观察之前命令窗口的变化情况

yaml 复制代码
 kubectl delete pod  my-tomcat-6d6b57c8c8-n5gm4

我们可以看到之前那个tomcat的pod被销毁,但是又重新启动了一个新的tomcat pod,

这是k8s的服务自愈功能,不需要运维人员干预

多副本

命令行的方式

yaml 复制代码
 # 创建3个副本
 kubectl create deployment my-tomcat --image=tomcat:9.0.55 --replicas=3

yaml方式

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  labels:
    app: tomcat-deployment
spec:
  replicas: 3  # 定义了 3 个副本
  selector:
    matchLabels:
      app: tomcat-deployment
  template:
    metadata:
      labels:
        app: tomcat-deployment
    spec:
      containers:
      - name: tomcat
        image: tomcat:9.0.55

扩缩容

yaml 复制代码
 # 扩容到5个pod
 kubectl scale --replicas=5 deployment my-tomcat
 # 缩到3个pod
 kubectl scale --replicas=3 deployment my-tomcat

 #修改 replicas
 kubectl edit deployment my-tomcat

滚动升级与回滚

对my-tomcat这个deployment进行滚动升级和回滚,将tomcat版本由tomcat:9.0.55升级到

tomcat:10.1.11,再回滚到tomcat:9.0.55

滚动升级:

yaml 复制代码
 kubectl set image deployment my-tomcat tomcat=tomcat:10.1.11 --record

可以执行 kubectl get pod -w 观察pod的变动情况,可以看到有的pod在销毁,有的pod在创建

查看pod信息

yaml 复制代码
 kubectl get pod

查看某个pod的详细信息,发现pod里的镜像版本已经升级了

yaml 复制代码
kubectl describe pod my-tomcat-85c5c8f685-lnkfm

版本回滚:

查看历史版本

yaml 复制代码
 kubectl rollout history deploy my-tomcat

回滚到上一个版本

yaml 复制代码
 kubectl rollout undo deployment my-tomcat     #--to-revision 参数可以指定回退的版本

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

查看pod详情,发现版本已经回退了

访问tomcat pod

集群内访问(在集群里任一worker节点都可以访问)

yaml 复制代码
 curl 192.168.36.74:8080

集群外部访问

当我们在集群之外访问是发现无法访问,那么集群之外的客户端如何才能访问呢?这就需要我们的

service服务了,下面我们就创建一个service,使外部客户端可以访问我们的pod

3.5 Service

创建service示例

命令行形式

yaml 复制代码
kubectl expose deployment my-tomcat --port=8080 --type=NodePort
yaml 复制代码
#查看service信息,port信息冒号后面的端口号就是对集群外暴露的访问接口
#NodePort范围在 30000-32767之间
kubectl get svc -owide


集群外部访问

使用集群节点的ip加上暴露的端口就可以访问

tomcat版本太高返回404的解决办法:进入tomcat容器,把 webapps 目录删除,再

把 webapps.dist 重命名为 webapps 即可。

yaml形式

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
   labels:
      app: my-tomcat
   name: my-tomcat  # Service 的名称
spec:
   ports:
   - port: 8080 #service的虚拟ip对应的端口,在集群内网机器可以访问用service的虚拟ip加该端口号访问
     nodePort: 30001 #Service在宿主主机上映射的外网访问端口,端口范围必须在30000~32767
     protocol: TCP
     port: 80  # Service 暴露的端口
     targetPort: 8080  # 被暴露的 Pod 的容器端口,一般与pod内部容器暴露的端口一致
   selector:
     app: my-tomcat
   type: NodePort  # Service 类型,可以是 ClusterIP、NodePort、LoadBalancer 等

3.6 存储

Volume

Volume指的是存储卷,包含可被Pod中容器访问的数据目录。容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同事无法在多个Pod中共享文件,通过使用存储卷可以解决这问题。

kubernetes 支持很多类型的卷。Pod可以同时使用任意数目的卷类型。临时卷类型的生命周期与Pod相同,但持久卷可以比Pod的存活期长。当Pod不再存在时,kubernetes 也会销毁临时卷;不过kubernetes 不会销毁永久卷。对于给定的Pod中任何类型的卷,在容器重启期间数据都不会丢失。

卷的核心就是一个目录,其中可能存有数据,Pod中的容器可以访问该目录中的数据。所采用的不同卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的东西。常见有confingMap、emptyDir、local、nfs、secret等。

  • ConfingMap:可以将配置文件以键值对的形式保存到ConfigMap中,并且可以在Pod中以文件或环境变量的形式使用。ConfigMap可以用来存储不敏感的配置信息,如应用程序的配置文件。
  • EmptyDir:是一个空目录,可以在Pod用来存储临时数据,当Pod删除时,该目录也会删除。
  • Local:将本地文件系统的目录或文件映射到Pod中的一个Volume中,可以用来在Pod中共享文件或数据。
  • NFS:将网络上的一个或多个NFS共享目录挂载到Pod中的Volume中,可以用来在多个Pod之间共享数据。
  • Secret:将敏感信息以密文的形式保存到Secret中,并且可以在Pod中以文件或环境变量的形式使用。Secret可以用来存储敏感信息,如用户的密码、证书等。

使用方式

使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts

字段中声明卷在容器中的挂载位置。 容器中的进程看到的文件系统视图是由它们的容器镜像的初始内

容以及挂载在容器中的卷(如果定义了的话)所组成的。 其中根文件系统同容器镜像的内容相吻合。

任何在该文件系统下的写入操作,如果被允许的话,都会影响接下来容器中进程访问文件系统时所看

到的内容。


搭建nfs文件系统

nfs(network filesystem ): 网络文件存储系统

安装nfs-server

yaml 复制代码
# 在每个机器。
 yum install -y nfs-utils
yaml 复制代码
 # 在master 执行以下命令
 echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
 
 # 执行以下命令,启动 nfs 服务;创建共享目录
 mkdir -p /nfs/data 
 
 # 在master执行10
 systemctl enable rpcbind
 systemctl enable nfs-server
 systemctl start rpcbind
 systemctl start nfs-server
 
 # 使配置生效
 exportfs -r 
 
 #检查配置是否生效
 exportfs
yaml 复制代码
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:
            - name: html
              nfs:
                 server: 192.168.23.201
                 path: /nfs/data/nginx-pv


测试通过,实现挂载

PV & PVC

基本使用


静态供应示例

创建PV池

yaml 复制代码
#nfs主节点1
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03

创建PV

yaml 复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01-10m
spec:
  capacity:
    storage: 10M
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  nfs:
    path: /nfs/data/01
    server: 192.168.23.201
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02-1gi
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  nfs:
    path: /nfs/data/02
    server: 192.168.23.201
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv03-3gi
spec:
  capacity:
    storage: 3Gi
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  nfs:
    path: /nfs/data/03
    server: 192.168.23.201

创建PVC

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 200Mi
  storageClassName: nfs

自动分配1G的

创建Pod绑定PVC

yaml 复制代码
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
          persistentVolumeClaim:
            claimName: nginx-pvc



动态供应

3.7 配置

ConfigMap

在 Kubernetes 中,ConfigMap 是一种用于存储非敏感信息的 Kubernetes 对象。它用于存储配置

数据,如键值对、整个配置文件或 JSON 数据等。ConfigMap 通常用于容器镜像中的配置文件、命令

行参数和环境变量等。

ConfigMap 可以通过三种方式进行配置数据的注入:

  1. 环境变量注入:将配置数据注入到 Pod 中的容器环境变量中。
  2. 配置文件注入:将配置数据注入到 Pod 中的容器文件系统中,容器可以读取这些文件。
  3. 命令行参数注入:将配置数据注入到容器的命令行参数中。

优点

  1. 避免了硬编码,将配置数据与应用代码分离。
  2. 便于维护和更新,可以单独修改 ConfigMap 而不需要重新构建镜像。
  3. 可以通过多种方式注入配置数据,更加灵活。
  4. 可以通过 Kubernetes 的自动化机制对 ConfigMap 进行版本控制和回滚。
  5. ConfigMap 可以被多个 Pod 共享,减少了配置数据的重复存储。

定义 ConfigMap

基本操作

yaml 复制代码
 # 查看 configmap
 $ kubectl get configmap/cm
 # 查看详细
 $ kubectl describe configmap/cm my-config
 # 删除 cm
 $ kubectl delete cm my-config
  • 命令行创建:

可以使用kubectl create configmap命令来创建configmap,具体命令如下:

yaml 复制代码
 kubectl create configmap my-config --from-literal=key1=value1 --from
literal=key2=value2

通过配置文件创建:推荐

可以通过创建YAML文件的方式来定义configmap的内容。例如,创建一个名为

内容如下:

  • 然后使用kubectl apply -f命令来创建configmap。

通过文件创建:

yaml 复制代码
 echo-n admin >./username
 echo -n 123456 > ./password
 kubectl create configmap myconfigmap --from-file=./username --from-file=./password

通过文件夹创建:

可以将多个配置文件放在同一个文件夹下,然后使用如:kubectl create configmap命令来创建configmap

yaml 复制代码
 kubectl create configmap my-config --from-file=config-files/

这将创建一个名为my-config的configmap,其中包含config-files/文件夹下所有的文件内容作为键值对。

通过环境变量创建:

可以将环境变量的值转换为configmap。例如,使用以下命令将当前环境变量的值转换为configmap:

yaml 复制代码
 kubectl create configmap my-config --from-env-file=<env>

使用示例

yaml 复制代码
 # docker安装redis
docker run -v /data/redis/redis.conf:/etc/redis/redis.conf \
-v /data/redis/data:/data \
-d --name myredis \
-p 6379:6379 \
redis:latest  redis-server /etc/redis/redis.conf

创建ConfigMap

通过文件的方式创建

yaml 复制代码
 #创建redis.conf 
 daemonize yes 
 requirepass root 
 
 # 创建配置,redis保存到k8s的etcd
 kubectl create cm redis-conf --from-file=redis.conf 

 #查看资源清单
 kubectl get cm redis-conf -oyaml

通过yaml的方式创建

yaml 复制代码
apiVersion: v1
 kind: ConfigMap
 metadata: 
  name: redis-conf 
 data: 
  redis.conf: | 
    maxmemory-policy allkeys-lru 
    requirepass root

创建Pod

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis
    command:
      - redis-server
      - "/redis-master/redis.conf"  #指的是redis容器内部的位置11
   # command: ["/bin/bash", "-ce", "tail -f /dev/null"]
    ports:
    - containerPort: 6379
    volumeMounts:
    - mountPath: /data
      name: data
    - mountPath: /redis-master
      name: config
  volumes:
    - name: data
      emptyDir: {}
    - name: config
      configMap:
        name: redis-conf
        items:
        - key: redis.conf
          path: redis.conf

测试

yaml 复制代码
 kubectl exec -it redis -- redis-cli 
 127.0.0.1:6379> config get  maxmemory-policy

Secret


定义 Secret

  • 使用命令行创建:

可以使用 kubectl create secret 命令来创建 secret,例如

yaml 复制代码
kubectl create secret generic my-secret --from-literal=username=admin --from-literal=password=admin123
  • 使用 YAML 文件定义:
    可以创建一个 YAML 文件来定义 Secret 对象,例如
yaml 复制代码
apiVersion: v1 
kind: Secret
metadata:
  name: my-secret 
type: Opaque 
data: 
  username: YWRtaW4= # base64 编码后的用户名 admin 
  password: MWYyZDFlMmU2N2Rm # base64 编码后的密码 1f2d1e2e67df

注意: 这个 YAML 文件定义了一个名为 my-secret 的 Secret 对象,其中包含了两个 base64 编码后的

key-value 对:username 和 password。

使用文件创建:

yaml 复制代码
echo -n admin >./username 
echo -n 123456 > ./password 
kubectl create secret generic mysecret --from-file=./username --from-file=./password
  • 通过环境变量创建:

可以将环境变量的值转换为secret。例如,使用以下命令将当前环境变量的值转换为secret:

yaml 复制代码
kubectl create secret generic  my-config --from-env-file=<env>

使用示例:从私有docker仓库拉取镜像

yaml 复制代码
 docker pull registry.cn-hangzhou.aliyuncs.com/fox666/tulingmall-product:0.0.5

无法从私有镜像仓库拉取镜像,抛出如下错误:

解决方案:使用 docker 的用户信息来生成 secret:

yaml 复制代码
 ##命令格式
kubectl create secret docker-registry myregistrykey \
 --docker-server=<你的镜像仓库服务器> \
 --docker-username=<你的用户名> \
 --docker-password=<你的密码> \
 --docker-email=<你的邮箱地址>
 
 
kubectl create secret docker-registry myregistrykey --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=fox666 --docker-password=xxx

在创建 Pod 的时候,通过imagePullSecrets来引用刚创建的myregistrykey

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: tulingmall-product
spec:
  containers:
  - name: tulingmall-product
    image: registry.cn-hangzhou.aliyuncs.com/fox666/tulingmall-product:0.0.5
  imagePullSecrets: 
  - name: myregistrykey 

3.8 Ingress

Ingress 是一种kubernetes资源类型,它允许kubernetes 集群中暴露HTTP和HTTPS服务。通过Ingress,你可以将流量路由到不同的服务和端口点,而无需使用不同的负载均衡器。Ingress通常使用Ingress Contrller实现,它是一个运行在kubernetes 集群中的负载均衡器,它根据Ingress规则下面是一个将所有流量都发送到同一Service的简单Ingress示例:

Ingress和Service区别

Ingress和Service都是kubernetes中用于将流量路由到应用的机制,但他们是在路由层面上有所不同:

  • Service是kubernetes中抽象的应用程序服务,它公开了一个单一的IP地址和端口,可以用于在kubernetes集群内部的Pod之间进行流量路由。
  • Ingress是一个kubernetes资源对象,它提供了对集群外部路由的规则。Ingress通过一个公共IP地址和端口将流量路由到一个或多个Service。

安装Ingress

yaml 复制代码
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
yaml 复制代码
#修改镜像
 vi deploy.yaml
 #1、将image k8s.gcr.io/ingress-nginx/controller:v0.46.0@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a的值改为如下值:
 registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0

2)安装ingress,执行如下命令

yaml 复制代码
 kubectl apply -f ingress-controller.yaml
  1. 查看是否安装成功
yaml 复制代码
kubectl get pod,svc -n ingress-nginx -owide

使用Ingress

官网地址:

yaml 复制代码
https://kubernetes.github.io/ingress-nginx/

配置ingress访问规则(就是类似配置nginx的代理转发配置),让ingress将域名tomcat.tuling.com

转发给后端的my-tomcat服务,新建一个文件ingress-tomcat.yaml,内容如下:

yaml 复制代码
apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata: 
  name: web-ingress
spec:
  rules: 
  - host: tomcat.tuling.com  #转发域名
    http:
      paths: 
      - pathType: Prefix
        path: /
        backend:
          service:
            name: my-tomcat
            port:
              number: 8080  #service的端口 

执行如下命令生效规则:

yaml 复制代码
kubectl apply -f ingress-tomcat.yaml 

查看生效的ingress规则:

yaml 复制代码
kubectl get ing

在访问机器配置host,win10客户机在目录:C:\Windows\System32\drivers\etc,在host里增加如

下host(ingress部署的机器ip对应访问的域名)

yaml 复制代码
 192.168.65.82  tomcat.tuling.com

配置完后直接在客户机浏览器访问http://tomcat.tuling.com:30940能正常访问tomcat。

Service&Ingress总结


4. K8S核心原理

4.1 K8S的网络模型

K8S的网络中主要存在4种类型的通信:

  • 同一Pod内的容器间通信
  • 各个Pod彼此间的通信
  • Pod和Service间的通信

集群外部流量和Service之间的通信

K8S为Pod和Service资源对象分别使用了各自的专有网络,Pod网络由K8S的网络插件配置实现,而

Service网络则由K8S集群进行指定。如下图:

K8S使用的网络插件需要为每个Pod配置至少一个特定的地址,即Pod IP。Pod IP地址实际存在于某个

网卡(可以是虚拟机设备)上。

而Service的地址却是一个虚拟IP地址,没有任何网络接口配置在此地址上,它由Kube-proxy借助

iptables规则或ipvs规则重定向到本地端口,再将其调度到后端的Pod对象。Service的IP地址是集群提

供服务的接口,也称为Cluster IP。

Pod网络和IP由K8S的网络插件负责配置和管理,具体使用的网络地址可以在管理配置网络插件时进行

指定,如10.244.0.0/16网络。而Cluster网络和IP是由K8S集群负责配置和管理,如10.96.0.0/12网

络。

从上图进行总结起来,一个K8S集群包含是三个网络。

  1. 节点网络:各主机(Master、Node、ETCD等)自身所属的网络,地址配置在主机的网络接口,用于各主机之间的通信,又称为节点网络。
  2. Pod网络:专用于Pod资源对象的网络,它是一个虚拟网络,用于为各Pod对象设定IP地址等网络参数,其地址配置在Pod中容器的网络接口上。Pod网络需要借助kubenet插件或CNI插件实现。
  3. Service网络:专用于Service资源对象的网络,它也是一个虚拟网络,用于为K8S集群之中的Service配置IP地址,但是该地址不会配置在任何主机或容器的网络接口上,而是通过Node上的kube-proxy配置为iptables或ipvs规则,从而将发往该地址的所有流量调度到后端的各Pod对象之上。

4.2 K8S的工作流程

用K8S部署Nginx的过程中,K8S内部各组件是如何协同工作的:

我们在master节点执行一条命令要master部署一个nginx应用(kubectl create deployment nginx --image=nginx)

yaml 复制代码
1. 这条命令首先发到master节点的网关api server,这是matser的唯一入口
2. api server将命令请求交给controller mannager进行控制
3. controller mannager 进行应用部署解析
4. controller mannager 会生成一次部署信息,并通过api server将信息存入etcd存储中
5. scheduler调度器通过api server从etcd存储中,拿到要部署的应用,开始调度看哪个节点有资源适合部署
6. scheduler把计算出来的调度信息通过api server再放到etcd中
7. 每一个node节点的监控组件kubelet,随时和master保持联系(给api-server发送请求不断获取最新数据),
   拿到master节点存储在etcd中的部署信息
8. 假设node2的kubelet拿到部署信息,显示他自己节点要部署某某应用
9. kubelet就自己run一个应用在当前机器上,并随时给master汇报当前应用的状态信息
10. node和master也是通过master的api-server组件联系的
11. 每一个机器上的kube-proxy能知道集群的所有网络,只要node访问别人或者别人访问node,
12. node上的kube
proxy网络代理自动计算进行流量转发

4.3 k8s架构原理六连问

K8S 是一个基于容器技术的分布式集群管理系统。既然是个分布式系统,那势必有多个 Node 节点(物理主机或虚拟机),它们共同组成一个分布式集群,并且这些节点中会有一个 Master 节点,由它来统一管理Node 节点。

如图所示:

问题一:主节点和工作节点是如何通信的呢?

首先,Master 节点启动时,会运行一个 kube-apiserver 进程,它提供了集群管理的 API 接口,是集群内各个功能模块之间数据交互和通信的中心枢纽,并且它也提供了完备的集群安全机制。

在 Node 节点上,使用 K8S 中的 kubelet 组件,在每个 Node 节点上都会运行一个 kubelet 进程,它负责向 Master 汇报自身节点的运行情况,如 Node 节点的注册、终止、定时上报健康状况等,以及接收 Master发出的命令,创建相应 Pod。

在 K8S 中,Pod 是最基本的操作单元,它与 docker 的容器有略微的不同,因为 Pod 可能包含一个或多个容器(可以是 docker 容器),这些内部的容器是共享网络资源的,即可以通过 localhost 进行相互访问。关于 Pod 内是如何做到网络共享的,每个 Pod 启动,内部都会启动一个 pause 容器(google的一个镜像),它使用默认的网络模式,而其他容器的网络都设置给它,以此来完成网络的共享问题。

如图所示:

问题二:Master 是如何将 Pod 调度到指定的 Node 上的?

该工作由 kube-scheduler 来完成,整个调度过程通过执行一些列复杂的算法最终为每个 Pod 计算出一个最佳的目标 Node,该过程由 kube-scheduler 进程自动完成。常见的有轮询调度(RR)。当然也有可能,我们需要将 Pod 调度到一个指定的 Node 上,我们可以通过节点的标签(Label)和 Pod 的 nodeSelector 属性的相互匹配,来达到指定的效果。

如图所示:

问题三:各节点、Pod 的信息都是统一维护在哪里的,由谁来维护?

从上面的 Pod 调度的角度看,我们得有一个存储中心用来存储各节点资源使用情况、健康状态、以及各Pod 的基本信息等,这样 Pod 的调度来能正常进行。

在 K8S 中,采用 etcd 组件 作为一个高可用强一致性的存储仓库,该组件可以内置在 K8S 中,也可以外部搭建供 K8S 使用。

集群上的所有配置信息都存储在了 etcd,为了考虑各个组件的相对独立,以及整体的维护性,对于这些存储数据的增、删、改、查,统一由 kube-apiserver 来进行调用,apiserver 也提供了 REST 的支持,不仅对各个内部组件提供服务外,还对集群外部用户暴露服务。

外部用户可以通过 REST 接口,或者 kubectl 命令行工具进行集群管理,其内在都是与 apiserver 进行通信。

如图所示:

问题四:外部用户如何访问集群内运行的 Pod ?

前面讲了外部用户如何管理 K8S,而我们更关心的是内部运行的 Pod 如何对外访问。使用过Docker 的同学应该知道,如果使用 bridge 模式,在容器创建时,都会分配一个虚拟 IP,该 IP 外部是没法访问到的,我们需要做一层端口映射将容器内端口与宿主机端口进行映射绑定,这样外部通过访问宿主机的指定端口,就可以访问到内部容器端口了。

那么,K8S 的外部访问是否也是这样实现的?答案是否定的,K8S 中情况要复杂一些。因为上面讲

的 Docker 是单机模式下的,而且一个容器对外就暴露一个服务。在分布式集群下,一个服务往往由多个Application 提供,用来分担访问压力,而且这些 Application 可能会分布在多个节点上,这样又涉及到了跨主机的通信。

这里,K8S 引入了 Service 的概念,将多个相同的 Pod 包装成一个完整的 service 对外提供服务,至于获取到这些相同的 Pod,每个 Pod 启动时都会设置 labels 属性,在 Service 中我们通过选择器 Selector,选择具有相同 Name 标签属性的 Pod作为整体服务,并将服务信息通过 Apiserver 存入 etcd 中,该工作由Service Controller 来完成。同时,每个节点上会启动一个 kube-proxy 进程,由它来负责服务地址到 Pod地址的代理以及负载均衡等工作。

如图所示:

问题五:Pod 如何动态扩容和缩放?

既然知道了服务是由 Pod 组成的,那么服务的扩容也就意味着 Pod 的扩容。通俗点讲,就是在需要时将Pod 复制多份,在不需要后,将 Pod 缩减至指定份数。K8S 中通过 Replication Controller 来进行管理,为每个 Pod 设置一个期望的副本数,当实际副本数与期望不符时,就动态的进行数量调整,以达到期望值。期望数值可以由我们手动更新,或自动扩容代理来完成。

如图所示:

问题六:各个组件之间是如何相互协作的?

最后,讲一下 kube-controller-manager 这个进程的作用。我们知道了 ectd 是作为集群数据的存储中心apiserver 是管理数据中心,作为其他进程与数据中心通信的桥梁。而 Service Controller、Replication Controller 这些统一交由 kube-controller-manager 来管理,kube-controller-manager 作为一个守护进程,每个 Controller 都是一个控制循环,通过 apiserver 监视集群的共享状态,并尝试将实际状态与期望不符的进行改变。关于 Controller,manager 中还包含了 Node 节点控制器(Node Controller)、资源配额管控制器(ResourceQuota Controller)、命名空间控制器(Namespace Controller)等。

如图所示:

相关推荐
前端 贾公子7 小时前
速通Docker === Dockerfile
运维·docker·容器
仇辉攻防17 小时前
【云安全】云原生-K8S-简介
web安全·网络安全·docker·云原生·容器·kubernetes·k8s
飞火流星0202718 小时前
CentOS7非root用户离线安装Docker及常见问题总结、各种操作系统docker桌面程序下载地址
docker·云原生·k8s·docker安装·docker离线安装·docker离线安装包下载·docker桌面程序下载地址
代码星辰21 小时前
Docker——入门介绍
运维·docker·容器
Linux运维老纪21 小时前
Linux 命令之技巧(Tips for Linux Commands)
linux·python·计算机网络·云原生·tomcat·云计算·运维开发
cxr82821 小时前
使用国内镜像加速器解决 Docker Hub 拉取镜像慢或被屏蔽的问题
运维·docker·容器
元气满满的热码式1 天前
K8S中高级存储之PV和PVC
云原生·容器·kubernetes
元气满满的热码式1 天前
K8S中的数据存储之基本存储
云原生·容器·kubernetes
yaoshengting1 天前
docker如何查看容器启动命令(已运行的容器)
运维·docker·容器
cxr8281 天前
Docker Desktop 解决从开发到部署的高效容器化工作流问题
运维·docker·容器