从B站学习的k8s相关基础,有兴趣的自行访问:Kubernetes(K8S) 入门进阶实战完整教程,黑马程序员K8S全套教程(基础+高级)_哔哩哔哩_bilibili
第一章 kubernetes介绍
本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念、组件和工作原理。
1.1 应用部署方式演变
缺点:不能威应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
2.虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
3.容器化部署:与虚拟化类似,但是共享了操作系统
(1)可以保证每个容器拥有自己的文件系统、cpu、内存、进程空间等
(2)运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
(3)容器化的应用程序可以跨云服务商,跨Linux操作系统发行版进行部署
容器化部署方式给带来了很多遍历,但是也会出现一些问题,比如说:
这些容器管理的问题统称威容器编排问题,为了解决这些容器编排问题,就产生了一些容器编排的软件
1.2 kubernets简介
kubernetes,是一个全新的基于容器技术的分部式架构领先方案,是谷歌严格保密几十年的秘密武器——Brog系统的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本
kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点钟的容器进行管理。他的目的就是实现资源管理的自动化,主要提供了如下的主要功能:
- 自我修复:一旦某一个容器崩溃,能够在1秒钟左右迅速启动新的容器
- 弹性伸缩:可以根据需要,自动对集群正在运行的容器数量进行调整
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
- 负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡
- 版本回退:如果发现新发布版本的程序版本有问题,可以立即回退到原来的版本
- 存储编排:可以根据容器子所生的需求自动创建存储卷
1.3 kubernetes组件
一个kubernetes集群主要是由控制节点(master)、工作系节点(node)构成,每个节点上都会安装不同的组件.
ApiServer:资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
Scheduler:负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
Controller-Manager: 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
Kubelet:负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
下面,以部署一个nginx服务来说明kubernetes系统各个组件调用关系:
1、首先明确,一旦kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中
2、一个nginx服务的安装请求会首先备发送到master节点的apiServer组件
3、apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上
在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
4、apiServer调用controller-manager去调度Node节点按住哪个nginx服务
5、kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod
pod是kubernetes的最小操作单位,容器必须泡在pod中至此
6、一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理
1.4 kubernetes概念
Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控
Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行
Pod:kubernetes的最小控制单元,容器都是运行在pod的,一个pod中可以有1个或者多个容器
Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等
Service:pod对外服务的统一入口,下面可以维护者同一类的多个pod
Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签
第二章 集群环境搭建
2.1 环境规划
2.1.1 集群类型
2.1.2 安装方式
kubenetes有多种部署方式,目前主流的方式有kubeadm、minkube、二进制包
- minikube:一个用于快速搭建单节点kubernetes的工具
- kubeadm:一个用于快速搭建kubernetes集群的工具
- 二进制包:从官网下载每个组件的二进制包,依次去安装,此方式对于理解kubernetes组件更加有效
- 说明:现在需要安装kubernetes的集群环境,但是又不想过于麻烦,所以选择使用kuberadm方式
2.1.3 主机规划
2.2 环境搭建
本次环境搭建需要安装三台linux系统(一主二从),内置CentOS7.9系统,然后每台linux中分别安装docker(18.06.3),kubeadm(1.17.4)、kubelet(1.17.4)、kubelctl(1.17.4)程序
2.2.1 主机安装
2.2.2 环境初始化
以下内容,三个主机节点均要做
#此方式下安装kubernetes集群要求CentOS版本再7.5或之上
给每个主机修改对应的名称,命令如下:
# 主机名为各主机的名(master、node1、node2)
[root@master ~] hostnamectl set-hostname 主机名
为了方便后面集群节点间的直接调用,再这配置一下主机名解析,企业中推荐使用内部DNS服务器
#主机名解析 编辑三天服务器的/etc/hosts文件,添加下面内容
kubernetes要求集群中的节点时间必须精确一致,这里直接使用chronyd服务从网络同步时间
#启动chronyd服务
[root@master ~]# systemctl start chronyd
#设置chronyd服务开机自启
[root@master ~]# systemctl enable chronyd
#chronyd服务启动稍等几秒钟,久可以使用date命令验证时间了
[root@master ~]# date
[root@master ~]# systemctl stop firewalld
[root@master ~]# systemctl disable firewalld
[root@master ~]# systemctl stop iptables
[root@master ~]# systemctl disable iptables
selinux是linux系统下的一个安全服务,如果不关闭它,在安装集群中会产生各种各样的奇葩问题
#编辑 /etc/selinux/config 文件。修改SELINUX的值为disabled
[root@master ~]# vim /etc/selinux/config
# 将SELINUX=Enforcing改成如下内容
SELINUX=disabled
swap分区指的是虚拟内存分区,他的作用是再物理内存使用完后,讲磁盘空间虚拟成内存来使用,启用swap设备会对系统得性能产生非常负面的影响,因此kubernetes要求么个节点都要禁用swap设备,但是如果因为某些原因不能关闭swap分区,就需要再集群安装过程中通过明确的参数进行配置说明
#编辑分区配置文件/etc/fstab,注释swap分区一行
#/dev/mapper/centos-swap swap swap defaults 0 0
#编辑/etc/sysctl.d/kubernetes.conf文件,添加如下配置:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
[root@master ~]# sysctl -p
[root@master ~]# modprobe br_netfilter
[root@master ~]# lsmod | grep br_netfilter
在kubernetes中service有两种模型,一种是基于iptables的,一种是基于ipvs的
两者相比较的话,ipvs的性能明显要高一些,但是如果要使用它,需要手动载入ipvs模块
[root@master ~]# yum install ipset ipvsadm -y
[root@master ~]# cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack_ipv4
EOF
[root@master ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
[root@master ~]# /bin/bash /etc/sysconfig/modules/ipvs.modules
[root@master ~]# lsmod | grep ip_vs
[root@master ~]# lsmod | grep nf_conntrack_ipv4
[root@master ~]# reboot
2.2.3 安装docker
[root@master ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum list docker-ce --showduplicates
#必须指定--setopt=obsoletes=0,否则yum会自动安装更高版本
[root@master ~]# yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y
#Docker在默认情况下使用Cgroup Driver为cgroupfs,而kubernetes推荐使用systemd来代替cgroupfs
[root@master ~]# mkdir /etc/docker
[root@master ~]# tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://o1o5o1sd.mirror.aliyuncs.com"]
}
EOF
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
[root@master ~]# systemctl enable docker
[root@master ~]# docker version
2.2.4 安装kubernetes组件
#由于kubernetes的镜像源在国外,速度比较慢,这里切换国内镜像源
#编辑/etc/yum.repos.d/kubernetes.repo,添加下面的配置
[kubernetes]
name=Kubernetes
baseurl=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
[root@master ~]# yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y
#编辑/etc/sysconfig/kubelet,添加下面的配置
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"
[root@master ~]# systemctl enable kubelet
2.2.5 准备集群镜像
#在安装kubernetes集群之前,必须要提前准备好集群需要的镜像,所需镜像可以通过下面命令查看
[root@master ~]# kubeadm config image list
#此镜像在kubernetes的仓库中,由于网络原因,无法连接,下面提供了一种替代方案,粘贴shell脚本代码,输入回车即可
images=(
kube-apiserver:v1.17.4
kube-controller-manager:v1.17.4
kube-scheduler:v1.17.4
kube-proxy:v1.17.4
pause:3.1
etcd:3.4.3-0
coredns:1.6.5
)
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
2.2.6 集群初始化
#创建集群,--kubernetes-version是版本号,--pod-network-cidr是pod网络,--service-cidr是service网络,--apiserver-advertise-address是master节点的地址
[root@master ~]# kubeadm init --kubernetes-version=v1.17.4 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --apiserver-advertise-address=masterIP地址
[root@master ~]# mkdir -p $HOME/.kube
[root@master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
#将node节点加入集群,初始化成功后会返回以下命令,可以直接粘贴执行,这些token值有时效性,建议初始化后立即加入节点,否则就要重新生成token值
节点添加完后,master节点上可以执行以下命令进行查看节点状态
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 2m12s v1.17.4
node1 NotReady <none> 16s v1.17.4
node2 NotReady <none> 9s v1.17.4
2.2.7 安装网络插件
kubernetes支持多种网络插件,比如flannel、calico、canal等等,人选一种使用即可,本次选择flannel
下面操作依旧只在master节点执行即可,插件使用的是DaemonSet的控制器,他会在每个节点上都运行
[root@master ~]# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
#修改文件中quay.io仓库为quay-mirror.qiniu.com
[root@master ~]# kubectl apply -f kub-flannel.yml
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 15h v1.17.4
node1 Ready <none> 15h v1.17.4
node2 Ready <none> 15h v1.17.4
2.3 服务部署
接下来在kubernetes集群中部署一个nginx程序,测试下集群是否在正常工作
[root@master ~]# kubectl create deployment nginx --image=nginx:1.14-alpine
[root@master ~]# kubectl expose deployment nginx --port=80 --type=NodePort
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-6867cdf567-2g84h 1/1 Running 0 59s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
service/nginx NodePort 10.100.197.13 <none> 80:31115/TCP 23s
第三章 资源管理
本章节主要介绍yaml语法和kubernetes的资源管理方式
3.1 资源管理介绍
在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes
kubernetes的本质上就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务,其实就是kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。
kubernetes的最小管理单元是pod而不是容器,所以只能将容器放在pod中,而kubernetes一般也不会直接管理Pod,而是通过Pod控制器来管理Pod的
当然,如果Pod中程序的数据需要持久化,kubernetes还提供了各种存储系统。
学习kubernetes的核心,就是学习如何对集群上的Pod、Pod控制器、Service、存储等各种资源进行操作
3.2 YAML语法介绍
YAML强调以数据为中心,并不是表示语言为重点、因而YAML本身的定义比较简单,号称“一种人性化的数据格式语言”。
- 纯量:单个的、不可再分的值
- 对象:键值对的集合,又称映射(mapping) / 哈希(HASH) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
#纯量,就是指的一个简单的值,字符串、布尔值、整数、浮点数、Null、时间、日期
c1: true(或者True)、false(或者False)
c2: 234
c5:2018-02-17 # 日期必须使用ISO 8601格式,即yyyy-MM-dd
c5:2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T链接,最后使用+代表时区
c7:heima # 简单写法,直接写值,如果字符传中间有特殊字符,必须使用双引号或者单引号包裹
line2 # 字符过多的情况可以拆分多行,每一行会被转化成一个空格
heima:{age:15,address:Beijing}
2、如果需要将多段yaml配置放在一个文件中,中间要使用 --- 分隔
3、下面是一个yaml转json的网站,可以通过它验证yaml是否书写正确
https://www.json2yaml.com/convert-yaml-to-json
3.3 资源管理方式
kubectl run nginx-pod --image=nginx:1.7.1 --port=80
kubectl create/patch -f nginx-pod.yaml
kubectl apply -f nginx-pod.yaml
3.3.1 命令式对象管理
kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。kuberctl命令的语法如下:
kubectl [command] [type] [name] [flags]
comand:指定要对资源执行资源执行的操作,例如create、get、delete
type:指定资源类型,比如deployment、pod、service
kubectl get pod pod_name -o yaml
kubernetes中所有的内容都抽象为资源,可以通过下面的命令进行查看:
kubernetes允许对资源进行多种操作,可以通过--help查看详细的操作命令
3.3.1 命令是对象管理
kubectl是kubernetes集群的命令行工具,通过它能够对集群上个今年新内容器化应用的安装部署,kubectl命令的语法如下:
kubectl [command] [type] [name] [flage]
- command:指定要对资源执行的操作,例如create、get、delete
- type:指定资源类型,比如deployment、pod、service
- name:指定资源的名称、名称大小写敏感
- flags:指定额外的可选参数
#查看所有pod
kubectl get pod
#查看某个pod
kubectl get pod pod_name
#查看某个个pod,以yaml格式展示结果
kubectl get pod pod_name -o yaml
kubernetes中所有的内容都抽象为资源,可以通过下面的命令进行查看:
kubernetes允许对资源进行多种操作,可以通过--help查看详细的操作命令
下面以一个namespace的创建和删除,简单演示下命令的使用:
[root@master ~]# kubectl create ns dev
[root@master ~]# kubectl get ns
[root@master ~]# kubectl run pod --image=nginx:1.17.1 -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl--generator=run-pod/v1 or kubectl create instead.
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pod-cbb995bbf-qv8lt 1/1 Running 0 36s
[root@master ~]# kubectl delete pod pod-cbb995bbf-qv8lt -n dev
pod "pod-cbb995bbf-qv8lt" deleted
[root@master ~]# kubectl delete ns dev
kubectl 的运行是需要进行配置的,他的配置文件时$HOME/.kube,如果想要再node节点运行此命令,需要将master上的.kube文件复制到node节点上,即再master节点上执行下面操作:
scp -r HOME/.kube node1 : HOME/
3.3.2 命令式对象配置
命令式对象配置就是使用命令配合配置文件一起来操作kubernetes资源
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Pod
metadata:
name: nginxpod
namespace: dev
spec:
containers:
- name: nginx-containers
[root@master ~]# kubectl create -f nginxpod.yaml
[root@master ~]# kubectl get -f nginxpod.yaml
NAME READY STATUS RESTARTS AGE
pod/nginxpod 1/1 Running 0 28s
[root@master ~]# kubectl delete -f nginxpod.yaml
命令式对象配置的方式操作资源,可以简单的认为:命令 + yaml配置文件(里面是命令需要的各种参数)
3.3.3 声明式对象配置
声明式对象配置跟命令式对象配置很相似,但是它只有一个命令apply
#首先执行一次kubctl apply -f yaml文件,发现创建了资源
[root@master ~]# kubectl apply -f nginxpod.yaml
#再次执行一次kubectl apply -f yaml文件,发现资源没有变动
[root@master ~]# kubectl apply -f nginxpod.yaml
其实声明式对象配置就是使用apply描述一个资源最终的状态(在yaml中定义状态)
如果资源不存在,就创建,相当于 kubectl create
创建/更新资源 使用声明式对象配置 kubectl apply -f xxx.yaml
删除资源 使用命令式对象配置 kubectl delete -f xxx.yaml
查询资源 使用命令式对象管理 kubectl get(describe) 资源名称
第四章 实战入门
本章节将介绍如何在kubernetes集群中部署一个nginx服务,并能够对其进行访问
4.1 Namespace
Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离
默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那次是就可以将两个Pod划分到不通的namespace下,kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同组的资源进行隔离使用和管理。
可以通过kubernetes的授权机制,将不通的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。
kubernetes在集群启动之后,会默认创建几个namespace
[root@node1 ~]# kubectl get namespace
default Active 28d # 所有未指定Namespace的对象都会被分配在default命名空间
kube-flannel Active 28d # 在Kubernetes集群中的每个节点上运行一个DaemonSet,用于部署和管理flanneld
kube-node-lease Active 28d # 集群节点之间的心跳维护,v1.13开始引入
kube-public Active 28d # 此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system Active 28d # 所有由Kubernetes系统创建的资源都处于这个命名空间
# 1 查看所有的ns 命令: kubectl get ns
[root@master ~]# kubectl get ns
# 2 查看指定ns 命令:kubectl get ns ns名称
[root@master ~]# kubectl get ns kube-system
# 3 指定输出格式 命令:kubectl get ns ns名称 -o 格式参数
# kubernetes支持的格式有很多,比较常见的是wide、json、yaml
[root@master ~]# kubectl get ns default -o yaml
creationTimestamp: "2023-10-08T10:17:52Z"
selfLink: /api/v1/namespaces/default
uid: dbc10978-556e-4589-8bf8-55d8a4a239a0
# 4 查看ns详情 命令: kubectl describe ns ns名称
[root@master ~]# kubectl describe ns default
Status: Active #Active 命名空间正在使用中 Terminaling 正在删除命名空间
# ResourceQuota 针对namespace做的资源限制
# LimitRange针对namespace中的每个组件做的资源限制
[root@master ~]# kubectl create ns dev
[root@master ~]# kubectl delete ns dev
apiVersion: v1
kind: Namespace
metadata:
创建:kubectl create -f ns-dev.yaml
删除:kubectl delete -f ns-dev.yaml
4.2 Pod
Pod是kubernetes集群进行管理的最小单元,程序要运行必须要部署在容器中,而容器必须要存在于Pod中
Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。
kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的。可以通过下main命令查看:
[root@master ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-6955765f44-6744x 1/1 Running 4 29d
coredns-6955765f44-6wh7j 1/1 Running 5 27d
kube-apiserver-master 1/1 Running 9 29d
kube-controller-manager-master 1/1 Running 12 29d
kube-flannel-ds-dcl6h 0/1 Init:ImagePullBackOff 2 29d
kube-flannel-ds-kd5q4 0/1 Init:ImagePullBackOff 2 29d
kube-flannel-ds-lgfsb 0/1 Init:ImagePullBackOff 2 29d
kube-proxy-4wbnc 1/1 Running 2 29d
kube-proxy-fzrml 1/1 Running 2 29d
kube-proxy-nw86k 1/1 Running 2 29d
kube-scheduler-master 1/1 Running 15 29d
kubernetes没有提供单独运行Pod的命令,都是通过Pod控制器来实现的
#命令格式: kubectl run (pod控制器名称) [参数]
[root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx-64777cd554-4z2tb 1/1 Running 0 19s
[root@master ~]# kubectl describe pod nginx-64777cd554-m94vx -n dev
Start Time: Thu, 23 Nov 2023 16:09:14 +0800
Labels: pod-template-hash=64777cd554
Controlled By: ReplicaSet/nginx-64777cd554
Container ID: docker://0cf1167eb68d15ed9c3a369ccb94354d898c6b854e1ecb6b4d6867e0f2f101ab
Image ID: docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
Started: Thu, 23 Nov 2023 16:09:15 +0800
/var/run/secrets/kubernetes.io/serviceaccount from default-token-2r657 (ro)
Type: Secret (a volume populated by a Secret)
SecretName: default-token-2r657
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Normal Scheduled 10m default-scheduler Successfully assigned dev/nginx-64777cd554-m94vx to node2
Normal Pulled 10m kubelet, node2 Container image "nginx:1.17.1" already present on machine
Normal Created 10m kubelet, node2 Created container nginx
Normal Started 10m kubelet, node2 Started container nginx
[root@master ~]# curl 10.244.2.12:80
<title>Welcome to nginx!</title>
font-family: Tahoma, Verdana, Arial, sans-serif;
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="nginx news">nginx.org</a>.<br/>
Commercial support is available at
<a href="Advanced Load Balancer, Web Server, & Reverse Proxy - NGINX">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
[root@master ~]# kubectl delete pod nginx-64777cd554-m94vx -n dev
pod "nginx-64777cd554-m94vx" deleted
[root@master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
nginx-64777cd554-qcfd5 0/1 ContainerCreating 0 15s
#这是因为当前Pod是由Pod控制器创建得,控制器会监控Pod状况,一旦发现Pod死亡,会立即重建
[root@master ~]# kubectl get deployment -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
[root@master ~]# kubectl delete deployment nginx -n dev
deployment.apps "nginx" deleted
[root@master ~]# kubectl get pod -n dev
No resources found in dev namespace.
创建:kubectl create -f pod-nginx.yaml
删除:kubectl delete -f pod-nginx.yaml
4.3 Label
Label是kubernetes系统中的一个重要概念。它的作用就是再资源上添加标识,用来对它们区分和选择。
- 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等等
- 一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去
- Label通常再资源对象定义时确定,当然也可以再对象创建后动态添加或者删除
可以通过Label实现资源的多维度的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。
- 版本标签:“version":"release",“version”:”stable“.......
- 环境标签:"environment":”dev","environment":"test","environment":"pro"
- 架构标签:"tier":"fontend","tier":"backend"
标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector,即:
Label selector用于查询和筛选拥有某些标签的资源对象
name = slave:选择所有包含Label种key="name"且value=“slave”的对象
env !=production:选择所有包括Label中的key=“env”且value不等于"production"的对象
name in (master,slave):选择所有包含Label中的key="name"且value=“master”或“slave”的对象
name not in (frontend):选择所有包含Label中的key="name"且value不等于”frontend“的对象
标签的选择条件可以试用多个,此时将多个Label Selector进行组合,试用逗号“,”分隔即可。例如:
name not in (fronternd),env!=production
[root@master ~]# kubectl get pod -n dev --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 9m52s <none>
[root@master ~]# kubectl label pod nginx -n dev version=1.0
[root@master ~]# kubectl label pod nginx -n dev version=2.0 --overwrite
[root@master ~]# kubectl get pod -n dev -l version=2.0 --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 27h tier=back,version=2.0
[root@master ~]# kubectl get pod -n dev -l version!=2.0 --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx1 1/1 Running 0 26h version=1.0
[root@master ~]# kubectl label pod nginx version- -n dev
然后就可以执行对应的更新命令了:kubectl apply -f pod-nginx.yaml
4.4 Deployment
在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建pod。
在kubernetes中Pod控制器的种类有很多,本章节只介绍一种:Deployment。
# 命令格式:kubectl run deployment 名称 [参数]
[root@master ~]# kubectl run nginx1 --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
[root@master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
nginx1-79d7bd676b-24qnv 1/1 Running 0 96m
nginx1-79d7bd676b-dvbwc 1/1 Running 0 96m
nginx1-79d7bd676b-hk6k2 1/1 Running 0 96m
[root@master ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
[root@master ~]# kubectl get deploy -n dev -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx1 3/3 3 3 2d1h nginx1 nginx:1.17.1 run=nginx1
[root@master ~]# kubectl describe deploy nginx1 -n dev
CreationTimestamp: Wed, 29 Nov 2023 10:12:14 +0800
Annotations: deployment.kubernetes.io/revision: 1
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
NewReplicaSet: nginx1-79d7bd676b (3/3 replicas created)
[root@master ~]# kubectl delete deploy nginx1 -n dev
deployment.apps "nginx1" deleted
4.5 Service
通过上小节的学习,已经能够利用Deployment来创建一组Pod来提供具有高可用性的服务。
虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题:
这样对于访问这个服务带来了难度。因此,kubernetes设计了Service来解决这个问题。
Service可以看作是一组同类Pod对外的访问接口。借助Service,应用可以方便地实现服务发现和负载均衡。
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
[root@master ~]# kubectl get svc svc-nginx1 -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
svc-nginx1 ClusterIP 10.111.61.3 <none> 80/TCP 38s run=nginx
# 这里产生了一个CLUSTER-IP,这就是service的IP,在Service的生命周期中,这个地址是不会变动的
[root@master ~]# curl 10.111.61.3:80
<title>Welcome to nginx!</title>
font-family: Tahoma, Verdana, Arial, sans-serif;
# 上面创建的Service的type类型为ClusterIP,这个IP地址只用集群内部可访问
# 如果需要创建外部也可以访问的Servie,需要修改type为NodePort
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
#此时查看,会发现出现了NodePort类型的Service,而且有一对Port(80:31118/TCP)
[root@master ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
svc-nginx1 ClusterIP 10.111.61.3 <none> 80/TCP 40m run=nginx
svc-nginx2 NodePort 10.107.207.143 <none> 80:31118/TCP 13s run=nginx
#接下来就可以通过集群外的主机访问 http://节点IP:31118 服务了
[root@master ~]# kubectl delete svc svc-nginx1 -n dev
创建:kubectl create -f svc-nginx.yaml
删除:kubectl delete -f svc-nginx.yaml
至此,已经掌握了Namespace、Pod、Deployment、Service资源的基本操作,有了这些操作,就可以再kubernetes集群中实现一个服务的简单部署和访问了,但是如果想要更好的使用kubernetes,就需要深入学习这几种资源的细节和原理。
第五章 Pod详解
5.1 Pod介绍
5.1.1 Pod结构
每个Pod中都可以包含一个或者多个容器,这些容器可以分为类型:
可以在根容器上设置ip地址,其他容器比ip(Pod IP),以实现Pod内部的网络通信
这里是Pod内部的通信,Pod的之间的通信采用虚拟二层网络技术来实现,我们当前环境用的是Flannel
5.1.2 Pod定义
namespace: string #Pod所属的命名空间,默认为"default"
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,入不指定,使用打包时使用的启动命令
- name: string #因公pod定义的共享存储卷的名称,需用volumes[ ]部分定义的卷名
mountPath: string #存储卷再容器内mount的绝对路径,英少于512字符
containerPort: int #容器需要监听的端口号
protocol: string #端口协议,支持TCP和UDP,默认TCP
cpu: string #CPU的限制,单位为core书,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于dokcer run --memory参数
cpu: string #CPU的限制,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
postStart: #容器启动后立即执行此钩子,如果执行失败,会更具重启策略进行重启
postStop: #容器终止前执行此钩子,无论结果如果,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
command: [string] #exec方式需要指定的命令或脚本
httpGet: #对Pod内容器健康检查方法设置为HttpGet,需要指定Path、port
tcpSocket: #对Pod内容器检查方式设置为tcpSocket方式
initialDelaySecond: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
restartPolicy: [Always | Never | onFailure ] #Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector
imagePullSecrets: #Pull镜像是使用secret名称,已key:secretkey格式指定
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
- name:string #共享存储卷名(volumes类型有很多种)
emptyDir: {} #类型为emptyDir的存储卷,于Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群于定义的secret对象到容器内部
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
#kubectl explain 资源类型 查看某种资源可以配置的一级属性
#kubectl explain 资源类型.属性 查看属性的子属性
[root@master ~]# kubectl explain pod
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
[root@master ~]# kubectl explain pod.metadata
- apiVersion <string> 版本,由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询到
- kind <string> 类型,由kubernetes内部定义,版本号必须可以用kubectl api-resources查询到
- metadata <Object> 元数据,主要是资源标识和说明,常用的由name、namespace、labels等
- spec <Object> 描述,只是配置中最重要的一部分,里面是对各种资源配置的详细描述
- status <Object> 状态信息,里面的内容不需要自定义,由kubernetes自动生成
在上面的属性中,spec是接下来研究的重点,继续看下他的常见子属性:
- contianers <[]Object> 容器列表,用于定义容器的详细信息
- nodeName <String> 根据nodeName的值蒋pod调度到指定的Node节点上
- nodeSelector <map[]> 根据NodeSelectort中定义的信息悬着蒋该Pod调度到包含这些label的Node上
- hostNetwork <boolean> 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主网络
- volumes <[]Object> 存储卷,用于定义Pod上面挂载的存储信息
- restartPolicy <string> 重启策略,表示Pod在遇到故障的时候的处理策略
5.2 Pod配置
本小节主要来研究 pod.spec.contianers 属性,这也是pod配置中最为关键的一项配置
[root@master ~]# kubectl explain pod.spec.containers
RESOURCE: containers <[]Object> #数组,代表可以有多个容器
imagePullPolicy <string> #镜像拉取策略
command <[]string> #容器的命令列表,如不指定,使用打包时使用的启动命令
resources <Object> #资源限制和资源请求的设置
5.2.1 基本配置
nginx:用1.17.1版本的nginx镜像创建(nginx是一个轻量级web容器)
busybox:用1.30版本的busybox镜像创建(busybox是一个小巧的linux命令合集)
[root@master ~]# kubectl create -f pod-base.yaml
#READY 1/2 :表示当前Pod中有2个容器,其中1个准备就绪,1个未就绪
#RESTARTS :重启次数,因为有1个容器故障了,Pod一直在重启试图恢复
[root@master ~]# kubectl get pods -n dev
5.2.2 镜像拉取
创建pod-imagepullpolicy.yaml文件,内容如下:
imagePullPolicy: Always #用于设置镜像拉取策略
imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:
- Always:总是从远程仓库拉取镜像(一直用远程下载)
- IfNotPresent:本地有则使用本地镜像(本地有就本地 本地没有就远程下载)
- Never:只是用本地镜像,从不去远程仓库拉取,本地没有就报错(一直使用本地下载)
如果镜像tag为具体版本号,默认策略时:IfNotPresent
如果镜像tag为:latest(最终版本),默认策略时always
[root@master ~]# kubectl create -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pod-imagepullpolicy 1/2 CrashLoopBackOff 3 2m2s
5.2.3 启动命令
在前面的案例中,一直有个问题没有解决,就是busybox容器一直没有成功运行,那么到底事什么原因导致这个容器的故障呢?
原来busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]
command,用于在pod中的容器初始化完毕之后运行一个命令。
touch /tmp/hello.txt; 创建一个/tmp/hello.txt 文件
while true;do /bin/echo $(date +%T)>> /tmp/hello.txt;sleep 3;done; 每隔3秒向文件中写入当前时间
[root@master ~]# kubectl create -f pod-command
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
#补充一个命令 kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行命令
[root@master ~]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker有点关系,kubernetes中的command、args两项其实是可以实现覆盖Dockerfile中ENTRYPOINT的功能。
1 如果commmand和args均没有写,那么Dockerfile的配置。
2 如果command写了,但args没有写,那么Dockerfile默认的默认的配置会被忽略,执行输入的command
3 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
4 如果command和args都写了,那么Dockerfile的配置会被忽略,执行command并追加上args参数
5.2.4环境变量
command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60;done;"]
[root@master ~]# kubectl create -f pod-env.yaml
[root@master ~]# kubectl exec pod-env -n dev -c busybox -it /bin/sh
这种方式不是很推荐,推荐将这些配置单独存储在配置文件中,这种方式将在后面介绍。
5.2.5 端口设置
本小节来介绍容器的端口暴露,也就是containers的ports选项。
[root@master ~]# kubectl explain pod.spec.containers.ports
name <string> #端口名称,如果指定,必须保证name在pod中是唯一的
containerPort <integer> #容器要监听的端口(0<x<65536)
hostPort <integer> #容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
hostIP <string> #要将外部端口绑定到主机IP(一般省略)
protocol <string> #端口协议。必须是UDP、TCP或SCTP。默认为"TCP"
接下来,编写以恶搞测试案例,创建pod-ports.yaml
[root@master ~]# kubectl create -f pod-ports.yaml
#在下面可以明显看到配置信息[root@master ~]# kubectl get pod pod-ports -n dev -o yaml
访问容器中的程序需要使用的是podIp:contianerPort
5.2.6 资源配额
容器中的程序要运行,肯定是要占用一定资源的,比如cpu和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其他容器无法运行。针对这种情况,kubernetes提供了对内存和cpu的资源进行配额的机制,这种机制主要通过resource选项实现,他有两个子选项:
接下来,编写一个测试案例,创建pod-resources.yaml
[root@master ~]# kubectl create -f pod-resources.yaml
[root@master ~]# kubectl get pod pod-resources -n dev
NAME READY STATUS RESTARTS AGE
pod-resources 1/1 Running 0 8m38s
[root@master ~]# kubectl get pod pod-resources -n dev -o yaml
[root@master ~]# kubectl describe pod pod-resources -n dev
Container ID: docker://eca379d6cac437e16a2c91047889f7d365517ec561dad5f683993e55bf565180
Image ID: docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
Started: Wed, 24 Jan 2024 09:45:17 +0800
[root@master ~]# kubectl delete -f pod-resources.yaml
#修改limits和requests参数,使其一致,都为2核cpu和10G内存
#运行pod,发现pod运行异常,这是由于当前环境没有满足这些需求的节点
[root@master ~]# kubectl create -f pod-resources.yaml
[root@master ~]# kubectl get pod pod-resources -n dev
NAME READY STATUS RESTARTS AGE
pod-resources 0/1 Pending 0 21s
5.3 Pod生命周期
我们一般将pod对象从创建至终得这段时间范围称为pod得生命周期,它主要包含下面得过程:
- 挂起(Pending):apiserver已经创建了pod资源对象,但它尚未备调度完成或人处于下载镜像的过程种
- 运行(Running):pod已经调度至某节点,并且所有容器都已经被kubelet创建完成
- 成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
- 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
- 未知(Unkonwn):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
5.3.1 创建和终止
- 用户通过kubectl或其他api客户端提交需要创建的pod信息给apiServer
- apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
- apiServer开始反映etcd中的pod对象的变化,其他组件使用watch机制来跟踪检查apiServer上的变动
- scheduler发现有新的pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer
- node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiSever
- apiServer及那个接收到的pod状态信息存入etcd中
- 用户向apiServer发送删除pod对象的命令
- apiServer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
- 将pod标记为terminating状态
- kubelet在监控到pod对向转为terminating状态的同时启动pod关闭过程
- 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此断电的service资源的端点列表中移除
- 如果当前pod对象定义了perStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
- pod对象中的容器进程收到停止信号
- 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
- kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
5.3.2 初始化容器
初始化容器实在pod的主容器启动之前要运行的容器,主要是做一些祝融其的前置工作,它具有两大特征:
假设要以主容器来运行nginx,但是要求在运行nginx之前先要能连接上mysql和redis所在服务器
为了简化测试,事先规定好mysql(172.20.45.153)和redis(172.20.45.154)服务器的地址
创建pod-initcontainer.yaml,内容如下:
command: ['sh','-c','until ping 172.20.45.153 -c 1; do echo waiting for mysql...;sleep 2;done;']
command: ['sh','-c','until ping 172.20.45.154 -c 1; do echo waiting for redis...;sleep 2;done;']