kubernetes 1.23.6
# 搭建K8S集群
- 服务器要求
- 三台服务器
- k8s-master 192.168.8.128
- k8s-node1 192.168.8.129
- k8s-node2 192.168.8.130
- 最低配置: 2核、2G内存、20G硬盘
- 最好联网,不能联网话需要提供对应镜像私有仓库
- 软件环境
- 操作系统: Centos7
- Docker: 20+
- k8s: 1.23.6 (在这个版本之上不支持Docker)
## 1. 安装步骤一: 初始化操作
```bash
systemctl stop firewalld
systemctl disable firewalld
# 关闭selinux,
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0
# 关闭 swap, 然后重启虚拟机
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 根据规划设置主机名
hostnamectl set-hostname <hostname>
# 添加 hosts
cat >> /etc/hosts << EOF
192.168.8.128 k8s-master1
192.168.8.129 k8s-node1
192.168.8.130 k8s-node2
EOF
# 系统调优
cat >> /etc/security/limits.conf << EOF
* soft nofile 655360
* hard nofile 655350
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
# 升级内核更新
rpm -import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
yum -y --enablerepo=elrepo-kernel install kernel-ml.x86_64 kernel-ml-devel.x86_64
yum update -y && grub2-set-default 1 && reboot
# 重启后查看内核是否是更新后的内核, uname -a
# 内核模块配置 注意: kernel < 4.19 使用 nf_conntrack_ipv4 并去除ip_vs_fo, kernel > 4.19 使用 nf_conntrack
yum install ipvsadm ipset sysstat conntrack libseccomp -y
cat >> /etc/modules-load.d/ipvs.conf << EOF
ip_vs
ip_vs_lc
ip_vs_wlc
ip_vs_rr
ip_vs_wrr
ip_vs_lblc
ip_vs_lblcr
ip_vs_dh
ip_vs_sh
ip_vs_fo
ip_vs_nq
ip_vs_sed
ip_vs_ftp
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF
systemctl enable --now systemd-modules-load.service
# 内核参数调优
cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
EOF
sysctl --system # 生效
# 时间同步。 写入计划任务比较好
yum install ntpdate -y
ntpdate time.windows.com
2. 安装步骤二: 安装基础软件(所有节点)
# 安装 Docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
yum install wget -y
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|grep "^doc"|sort -r
yum -y install docker-ce-20.10.23-3.el7
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://c1ncp8uc.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
systemctl daemon-reload
systemctl enable docker
systemctl start docker
docker --version
# 添加阿里云 yum 源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 安装 kubeam、kubelet、kubectl
yum install -y kubelet-1.23.6 kubeadm-1.23.6 kubectl-1.23.6
systemctl enable kubelet
systemctl start kubelet
3. 安装步骤三: 部署 Kubernetes Master
# 在 Master 节点下执行
kubeadm init \
--apiserver-advertise-address=192.168.8.128 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.6 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
# 或者把初始化参数导出成配置文件: kubeadm config print init-defaults > kubeadm-calico.conf
# 查看一下对应的镜像版本,确定配置文件是否生效: kubeadm config images list --config kubeadm-calico.conf
# 确认没问题之后我们直接拉取镜像: kubeadm config images pull --config kubeadm-calico.conf
# 初始化: kubeadm init --config kubeadm-calico.conf
# 初始化安装成功后,复制如下配置并执行,会生成一个加入集群的命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 如果初始化失败后,一般是 kubelet 问题,查错误日志: journalctl -xefu kubelet
# 解决之后,再重置下: kubeadm reset , 然后再初始化
# 查看节点
kubectl get no
4. 安装步骤四: 加入 Kubernetes Node
# 如果 token 已经过期,就重新申请
kubeam token create --print-join-command
# token 没有过期忘记了。可以通过如下命令获取
kubeadm token list # 获取 token 名字
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt |openssl rsa -pubin -outform der 2>/dev/null |openssl dgst -sha256 -hex |sed 's/^.* //' # 获取 hash 值
kubeadm join <address>:<port> --token <token_name> --discovery-token-ca-cert-hash sha256:<Hash值>
# 查看机器状态
[root@k8s-master1 ~]# kubectl get no -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master1 NotReady control-plane,master 13m v1.23.6 192.168.8.128 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.24
k8s-node1 NotReady <none> 3m19s v1.23.6 192.168.8.129 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.23
k8s-node2 NotReady <none> 17s v1.23.6 192.168.8.130 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.23
[root@k8s-master1 ~]# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
scheduler Healthy ok
[root@k8s-master1 ~]# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-6d8c4cb4d-7cb48 0/1 Pending 0 18m # 一般是因为网络的问题,所以一直 Pending
coredns-6d8c4cb4d-vp9hb 0/1 Pending 0 18m
etcd-k8s-master1 1/1 Running 0 18m
kube-apiserver-k8s-master1 1/1 Running 0 18m
kube-controller-manager-k8s-master1 1/1 Running 0 18m
kube-proxy-f4clb 1/1 Running 0 18m
kube-proxy-jbgm7 1/1 Running 0 7m42s
kube-proxy-nqm7d 1/1 Running 0 4m40s
kube-scheduler-k8s-master1 1/1 Running 0 18m
5. 安装步骤五:部署 CNI 网络插件
https://docs.tigera.io/archive/ 选择与 kubernetes 对应的版本 https://docs.tigera.io/archive/v3.23/getting-started/kubernetes/quickstart 这里使用: Tigera 操作員來安裝 Calico
# 在 Master 节点执行
cd /opt
curl -O https://projectcalico.docs.tigera.io/archive/v3.23/manifests/tigera-operator.yaml
curl -O https://projectcalico.docs.tigera.io/archive/v3.23/manifests/custom-resources.yaml
# 搜索 CALICO_IPV4POOL_CIDR ,修改为 kubeadm 初始化对应的 --pod-network-cidr=10.244.0.0/16 地址
vi custom-resources.yaml
cidr: 10.244.0.0/16
# 部署
kubectl create -f ./tigera-operator.yaml -f ./custom-resources.yaml
# 删除 kubectl delete -f calico.yaml
# 等到每個 pod 都有`STATUS`的`Running`
watch kubectl get pods -n calico-system
效果
[root@k8s-master1 opt]# kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-apiserver calico-apiserver-7f8fcc8dcb-vtqrh 1/1 Running 0 5m7s
calico-apiserver calico-apiserver-7f8fcc8dcb-xxbp4 1/1 Running 0 5m7s
calico-system calico-kube-controllers-7b66454db8-xgsm8 1/1 Running 0 9m11s
calico-system calico-node-4lt8d 1/1 Running 0 9m12s
calico-system calico-node-h6msh 1/1 Running 0 9m12s
calico-system calico-node-xcbtf 1/1 Running 0 9m12s
calico-system calico-typha-79659df74c-l6nk2 1/1 Running 0 9m12s
calico-system calico-typha-79659df74c-w68jf 1/1 Running 0 9m12s
kube-system coredns-6d8c4cb4d-7cb48 1/1 Running 0 136m
kube-system coredns-6d8c4cb4d-vp9hb 1/1 Running 0 136m
kube-system etcd-k8s-master1 1/1 Running 0 136m
kube-system kube-apiserver-k8s-master1 1/1 Running 0 136m
kube-system kube-controller-manager-k8s-master1 1/1 Running 0 136m
kube-system kube-proxy-f4clb 1/1 Running 0 136m
kube-system kube-proxy-jbgm7 1/1 Running 0 125m
kube-system kube-proxy-nqm7d 1/1 Running 0 122m
kube-system kube-scheduler-k8s-master1 1/1 Running 0 136m
tigera-operator tigera-operator-7885599d97-ndwr4 1/1 Running 0 9m51s
[root@k8s-master1 opt]# kubectl get no -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master1 Ready control-plane,master 137m v1.23.6 192.168.8.128 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.24
k8s-node1 Ready <none> 126m v1.23.6 192.168.8.129 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.23
k8s-node2 Ready <none> 123m v1.23.6 192.168.8.130 <none> CentOS Linux 7 (Core) 6.4.1-1.el7.elrepo.x86_64 docker://20.10.23
calicoctl是用来查看管理calico的命令行工具,定位上有点类似于calico版本的kubectl (可不安装)
参考: https://docs.tigera.io/archive/v3.23/maintenance/clis/calicoctl/install
6. 测试 Kubernetes 集群
# 创建部署
kubectl create deploy nginx --image=nginx
# 暴露端口
kubectl expose deploy nginx --port=80 --type=NodePort
# 查看 pod 以及服务信息
kubectl get pod,svc
# 访问节点 http://<IP>:<PORT>
7. 命令行工具 kubectl
api-server 只有 master 上可以执行,为了让所有节点都可以与 api-server 通信
# 1. 将 master 节点中 /etc/kubernetes/admin.conf 拷贝到需要运行的服务器的 /etc/kubernetes 目录中
scp /etc/kubernetes/admin.conf root@k8s-node1:/etc/kubernetes
# 2. 在对应的服务器上配置环境变量
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile
# 3. 在 node 节点测试命令
kubectl get no
K8S的资源清单
必须存在的属性
| 参数名 | 字段类型 | 说明 |
| --- | --- | --- |
| version | String | k8s的api版本,目前基本时v1,可以用kubectl api-versions命令查询 |
| kind | String | 指yaml文件定义的资源类型和角色,比如Pod |
| metadata | Object | 元数据对象,固定值写metadata |
| metadata.name | String | 元数据对象的名称,由我们编写,比如Pod的名字 |
| metadata.namespace | String | 元数据对象的命名空间,由我们自身定义 |
| spec | Object | 详细定义对象,固定值写spec |
| spce.containers\[\] | list | spec对象的容器列表 |
| spce.containers\[\].name | String | 定义容器的名称 |
| spce.containers\[\].image | String | 定义容器的镜像 |
主要对象
| 参数名 | 字段类型 | 说明 |
| --- | --- | --- |
| spce.containers\[\].name | String | 定义容器的名称 |
| spce.containers\[\].image | String | 定义容器的镜像 |
| spce.containers\[\].imagePullPolicy | String | 镜像的拉取策略 <br>Always:每次都拉取新的镜像 <br>Never:仅使用本地镜像,从不拉取 <br>IfNotPresent:如果本地有就使用本地镜像,没有则拉取,不写默认Always <br>建议使用IfNotPresent,因为docker中latest不是固定值,经常变 |
| spce.containers\[\].command\[\] | list | 容器的启动命令,因为是数组可以指定多个,不指定则使用镜像打包中的命令 |
| spce.containers\[\].args\[\] | list | 容器启动命令的参数,因为是数组可以指定多个 |
| spce.containers\[\].workingDir | String | 容器的工作目录 |
| spce.containers\[\].volumeMounts\[\] | list | 容器内部存储卷位置 |
| spce.containers\[\].volumeMounts\[\].name | String | 容器挂载的存储卷名称 |
| spce.containers\[\].volumeMounts\[\].mountPath | String | 容器挂载的存储卷路径 |
| spce.containers\[\].volumeMounts\[\].readOnly | String | 容器挂载的存储卷读写模式,true或false,默认true只读 |
| spce.containers\[\].ports\[\] | list | 容器用到的端口列表 |
| spce.containers\[\].ports\[\].name | String | 指定端口名称 |
| spce.containers\[\].ports\[\].containerPort | String | 指定容器需要监听的端口 |
| spce.containers\[\].ports\[\].hostPort | String | 指定容器所在主机需要监听的端口号,默认和containerPort相同,注意设置了hostPort同一台主机无法启动该容器的形同副本(因为主机的关端口号不能相同,这样会冲突) |
| spce.containers\[\].ports\[\].protocol | String | 指定端口的协议,支持TCP和UDP,默认TCP |
| spce.containers\[\].env\[\] | list | 指定容器运行前所需设置的环境变量列表 |
| spce.containers\[\].env\[\].name | String | 环境变量名称 |
| spce.containers\[\].env\[\].value | String | 指定环境变量值 |
| spce.containers\[\].resources | Object | 资源限制和资源请求的值 |
| spce.containers\[\].resources.limits | Object | 容器运行时资源上限(运行容器所能用的最大资源) |
| spce.containers\[\].resources.limits.cpu | String | CPU的限制,单位为core数,将用于docker run --CPU-shares参数 |
| spce.containers\[\].resources.limits.memory | String | 内存限制,单位为MIB、GIB |
| spce.containers\[\].resources.requests | Object | 容器启动和调度的限制(运行容器所需最小资源) |
| spce.containers\[\].resources.requests.cpu | String | CPU的限制,单位为core数 |
| spce.containers\[\].resources.requests.memory | String | 内存限制,单位为MIB、GIB |
额外参数
| 参数名 | 字段类型 | 说明 |
| --- | --- | --- |
| spec.restartPolicy | String | Pod的重启策略 <br>Always:Pod一旦终止运行,无论容器时如何终止的,kubelet服务都将它重启,默认 <br>Onfailure:只有Pod以非零退出吗终止时,kubelet才会重启该容器,正常结束退出码为0 <br>Never:Pod终止后,kubelet将退出码报告给master不会重启 |
| spec.nodeSelector | Object | 定义Node的label过滤标签,以key:value格式指定 |
| spec.imagePullSecrets | Object | 定义pull镜像时使用的secret名称,以name:secretkey格式指定 |
| spec.hostNetwork | boolean | 定义是否使用主机网络模式,默认false,设置true表示使用宿主机网络 <br>不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本 |
version说明
# 查看当前k8s支持的version
kubectl api-versions
# 查看某个资源支持的版本 比如Pod
kubectl explain pod 或者 kubectl explain pod.apiVersion(可在FIELDS选择字段中选择具体字段,详细查看)
KIND: Pod
VERSION: v1
深入Pod
1. 配置文件
# vim 手🦌一个配置 Pod 文件
[root@k8s-master1 ~]# cat nginx-demo.yaml
apiVersion: v1 # api 文档版本
kind: Pod # 资源对象类型,也可以配置为 Deployment、Statefulset 这一类的对象
metadata: # Pod 相关的元数据,类似表述 Pod 的数据
name: nginx-demo # Pod 名称
labels: # 定义 Pod 标签
type: app # 自定义 label 标签, k 为 type, v 为app
version: 1.0.0 # 自定义 label 标签, Pod 版本号
namespace: 'default' # 命名空间的配置
spec: # 期望Pod按照这里面的描述进行创建containers: #对于Pod中的容器描述
containers: # 对于Pod中的容器描述
- name: nginx #容器的名称
image: nginx:1.7.9 #指定容器的镜像
imagePullPolicy: IfNotPresent #镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
command: # 指定容器启动时执行的命令
- nginx
- -g
- 'daemon off;' # nginx -g 'daemon off; '
workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
ports:
- name: http # 端口名称
containerPort: 80 # 描述容器内要暴露什么端口
protocol: TCP # 描述该端口是基于哪利协议通信的
env: # 坏境变量
- name: JVM_OPTS # 环境变量名称
value: '-Xms128m -Xmx128m' # 环境变量的值
resources:
requests: # 最少需要多少资源
cpu: 100m # 限制cpu最少使用0.1个核心
memory: 128Mi # 限制内存最少使用128兆
limits: # 最多可以用多少资源
cpu: 200m # 限制cpu最多使用0.2个核心
memory: 256Mi # 限制最多使用256兆
restartPolicy: OnFailure # 重启策略,只有失败的情况才会重启
[root@k8s-master1 ~]# kubectl create -f nginx-demo.yaml
pod/nginx-demo created
[root@k8s-master1 ~]# watch kubectl get po
# IP 地址分配的是 提前定义要的 pod 地址段里
[root@k8s-master1 ~]# kubectl get po nginx-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-demo 1/1 Running 0 27m 10.244.169.131 k8s-node2 <none> <none>
[root@k8s-master1 ~]# route -n
......
10.244.169.128 192.168.8.130 255.255.255.192 UG 0 0 0 ens33 # 10.244.169.0 段落
......
2. 探针
- 探针类型
- StartupProbe (启动探针)
- 当配置了 startupProbe后,会先禁用其他探针, 直到 startupProbe成功后,其他探针才会继续。
- LivenessProbe (存活探针)
- 用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器自动成功,不会执行重启策略。
- ReadinessProbe (健康探针)
- 用于探测容器内的程序是否健康,它的返回值如果返回success, 那么就队为该容器已经完全启动,并且该容器是可以接收外部流量的。
- 探针探测方式
- ExecAction
- 在容器内部执行一个命令,如果返回值为0,则任务容器时健康的。
- TCPSocketAction
- 通过tcp连接监测容器内端口是否开放。如果开放则证明该容器健康
- HTTPGetAction
- 生产环境用的较多的方式,发送HTTP请求到容器内的应用程序,如果接口返回的状态码在200~400之间,则认为容器健康。
- 参数配置
- initialDelaySeconds: 60 # 初始化时间
- timeoutSecords: 2 # 超时时间
- periodSeconds: 5 # 监测间隔时间
- successThreshold: 1 # 检查1次成功就表示成功
- failureThreshold:2 # 监测失败2次就表示失败
StartupProbe 探针
# 基于上面创建 pod 方式, 测试: StartupProbe 启动探针、livenessProbe 存活探针、ReadinessProbe 就绪探针
...略
imagePullPolicy: IfNotPresent #镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
startupProbe: # 应用启动探针配置
#httpGet: # 探测方式,基于 http 请求探测
# path: /index.html
tcpSocket: # 探测方式,基于 tcp 请求探测
port: 80 # 请求端口
#exec: # 探测方式,基于 cmd 请求探测
# command:
# - sh
# - -c
# - "sleep3; echo success > /inited"
failureThreshold: 3 # 失败多少次才算真正的失败
periodSeconds: 10 # 间隔时间
successThreshold: 1 # 多少次监测成功算成功
timeoutSeconds: 5 # 请求的超时时间
livenessProbe: # 应用存活探针配置
httpGet: # 探测方式,基于 http 请求探测
path: /index.html
port: 80
failureThreshold: 3 # 失败多少次才算真正的失败
periodSeconds: 10 # 间隔时间
successThreshold: 1 # 多少次监测成功算成功
timeoutSeconds: 5 # 请求的超时时间
readinessProbe: # 应用就绪探针配置
httpGet: # 探测方式,基于 http 请求探测
path: /index.html
port: 80
failureThreshold: 3 # 失败多少次才算真正的失败
periodSeconds: 10 # 间隔时间
successThreshold: 1 # 多少次监测成功算成功
timeoutSeconds: 5 # 请求的超时时间
...略
[root@k8s-master1 ~]# kubectl describe po nginx-demo | grep -E "Liveness|Readiness|Startup"
Liveness: http-get http://:80/index.html delay=0s timeout=5s period=10s #success=1 #failure=3 # 其次:存活检测
Readiness: http-get http://:80/index.html delay=0s timeout=5s period=10s #success=1 #failure=3 # 其次:就绪检测
Startup: tcp-socket :80 delay=0s timeout=5s period=10s #success=1 #failure=3 # 首先: 启动检测
3. 生命周期
# 基于上面创建 pod 方式, 测试:生命周期
...略
spec: # 期望Pod按照这里面的描述进行创建containers: #对于Pod中的容器描述
terminationGracePeriodSeconds: 30 # 当pod被删除时,给这个pod宽限多长时间
containers: # 对于Pod中的容器描述
- name: nginx #容器的名称
image: nginx:1.7.9 #指定容器的镜像
imagePullPolicy: IfNotPresent #镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
lifecycle: # 生命周期的配置
postStart: # 生命周期启动阶段做的事情,不一定在容器的前运行
exec:
command:
- sh
- -c
- "echo '<h1>pre stop<h1>' > /usr/share/nginx/html/prestop.httml"
preStop:
exec:
command:
- sh
- -c
- "sleep 50; echo 'sleep finished...' >> /usr/share/nginx/html/prestop.html"
...略
资源调度
Lable 和 Selector
kubectl get po -l type=app # 搜索标签 type=app
kubectl get po -A -l type=app # 搜索所有命名空间标签 type=app
kubectl get po -A -l type=app --show-labels # 搜索 type=app, 并显示详细标签信息
kubect get po -l "type in (app,app1,app2)" # 搜索标签 type 包含其中一个值标签
kubect get po -l version!=1.0.0,type=app # 搜索多标签 version!=1.0.0,type=app
Deployment 无状态
创建
kubectl create deploy nginx --image=nginx
[root@k8s-master1 ~]# kubectl get deploy,rs,po -l app=nginx --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
deployment.apps/nginx 1/1 1 1 6h28m app=nginx
NAME DESIRED CURRENT READY AGE LABELS
replicaset.apps/nginx-85b98978db 1 1 1 6h28m app=nginx,pod-template-hash=85b98978db
NAME READY STATUS RESTARTS AGE LABELS
pod/nginx-85b98978db-259bm 1/1 Running 0 3h7m app=nginx,pod-template-hash=85b98978db
[root@k8s-master1 ~]# kubectl get deploy nginx -o yaml > nginx-deploy.yaml
# 修改如下
apiVersion: apps/v1 # deployment api版本
kind: Deployment # 资源类型为deployment
metadata: # 元信息
labels: # 标签
app: nginx-deploy # 具体的 key: value配置形式
name: nginx-deploy # deployment的名字
namespace: default # 所在的命名空间
spec:
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
selector: # 选择器,用于找到匹配的RS
matchLabels: # 按照标签匹配
app: nginx-deploy # 匹配的标签
strategy: # 更新策略
rollingUpdate: # 滚动更新配HI
maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod模板
metadata: # pod 的元信息
labels: # pod的标签
app: nginx-deploy
spec: # pod期望信息
containers: # pod的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: Always # 重启策略
name: nginx # 容器名称
restartPolicy: Always # 删除操作最多宽限多长时间■
[root@k8s-master1 ~]# kubectl delete deploy nginx # 删除临时
[root@k8s-master1 ~]# kubectl create -f nginx-deploy.yaml # 使用 yml 文件的方式创建 deploy
滚动更新
由于当前副本数只有一个,我们扩容一下
只有修改 容器部分 containers ,才会滚动更新
# 扩容不是滚动更新
kubectl edit deploy nginx-deploy
replicas: 3 # 期望副本数
# 修改下镜像,保存执行滚动更新
kubectl edit deploy nginx-deploy # 或者命令方式 kubectl set image deployment/nginx-deploy nginx=nginx:1.8
- image: nginx:1.8 # 修改下镜像
# 观察自滚动更新状态
[root@k8s-master1 ~]# kubectl rollout status deploy nginx-deploy
Waiting for deployment "nginx-deploy" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deploy" successfully rolled out
回归版本
比如操作失误,导致更新的pod无法启动,那么我们想回滚到上一个版本
# 查看更新的历史版本
kubectl rollout history deploy nginx-deploy
# 查看历史版本号的详细信息
kubectl rollout history deployment/nginx-deploy --revision=<REVISION>
# 回滚到历史版本号
kubectl rollout undo deployment/nginx-deploy --to-revision=<REVISION>
扩容缩容
kubectl scale --replicas=6 deploy nginx-deploy # 扩容到 6个 pod, template 没有改变,不会更改 rs
kubectl scale --replicas=3 deploy nginx-deploy # 缩容到 3个 pod
滚动更新的暂停和恢复
常用于增加pod或者服务器的时候
kubectl rollout pause deploy nginx-deploy # 滚动更新暂停
# 修改之后: 不会自动更新,只有恢复的时候才会更新
kubectl rollout resume deploy nginx-deploy # 滚动更新恢复
StatefulSet 有状态
创建
由于没有 存储卷,这里就不设置了
# statefulset.yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet # StatefulSet类型的资源
metadata:
name: web
spec:
serviceName: "nginx" # 使用哪个service来管理
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports: # 容器内部要暴露的端口
- containerPort: 80 # 具体暴露的端口号
name: web # 该端口配置的名字
# volumeMounts: # 加教数据卷
# - name: www # 指定加载哪个数据卷
# mountPath: /usr/share/nginx/html # 加载到容器中的哪个目录
# volumeClaimTemplates: # 数据卷模板
# - metadata: # 数据卷描述
# name: www # 数据卷的名称
# annotations: # 数据卷的注解
# volume.alpha.kubernetes.io/storage-class: anything
# spec: # 数据卷的规约
# accessModes: ["ReadWriteOnce"] # 访问模式
# resources:
# requests:
# storage: 1Gi # 需要1G的存储资源
[root@k8s-master1 ~]# kubectl create -f statefulset.yaml
service/nginx created
statefulset.apps/web created
[root@k8s-master1 ~]# kubectl get sts,svc,pod
NAME READY AGE
statefulset.apps/web 2/2 9s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12h
service/nginx ClusterIP None <none> 80/TCP 9s
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 9s
pod/web-1 1/1 Running 0 7s
扩容和缩容
[root@k8s-master1 ~]# kubectl scale sts web --replicas=4 # 命令方式
statefulset.apps/web scaled
[root@k8s-master1 ~]# kubectl patch sts web -p '{"spec":{"replicas": 32}}' # json 方式
statefulset.apps/web patched
[root@k8s-master1 ~]# kubectl get sts
NAME READY AGE
web 2/2 9m51s
滚动更新
镜像更新(目前还不支持直接更新image,需要patch来间接实现) 和 deployment 类似
- StatefulSet也可以采用滚动更新策略,同样是修改pod
- template属性后会触发更新,但是由于pod是有序的,在 StatefulSet中更新时是基于pod的顺序倒序更新的
kubectl patch sts web --type='json' -p='[{"op": "replace","path": "/spec/template/spec/containers/0/image", "value": "nginx:1.8"}]'
灰布发布/金丝雀发布
目标: 将项目上线后产生问题的影响,尽量降到最低
过程: 先更新一部分,如果正常没有问题了,再逐渐更新
利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效 例如我们有5个pqd.如果当前 partition 设置为3,那么此时滚动更新时,只会更新那些序号 >= 3的pod 利用该机制,我们可以通过控制partition的值,来决定只更新其中一部分pod,确认没有问题后再主健增大更新的pod数量,最终实现全部pod更新
[root@k8s-master1 ~]# kubectl patch sts web -p '{"spec":{"replicas": 5}}'
statefulset.apps/web patched
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 25m
web-1 1/1 Running 0 25m
web-2 1/1 Running 0 3m8s
web-3 1/1 Running 0 3m6s
web-4 1/1 Running 0 21s
[root@k8s-master1 ~]# kubectl describe po web-4 |grep "Image:"
Image: nginx:1.8
[root@k8s-master1 ~]# kubectl describe po web-0 |grep "Image:"
Image: nginx:1.8
[root@k8s-master1 ~]# kubectl edit sts web # 修改,实现金丝雀发布,只更新一部分,这里设置只更新三个
partition: 3
[root@k8s-master1 ~]# kubectl describe po web-0 |grep "Image:" # <3 的未更新
Image: nginx:1.8
[root@k8s-master1 ~]# kubectl describe po web-3 |grep "Image:" # 发现只更新了一小部分 >=3 的pod
Image: nginx:1.7.9
# 最后完全没问题了,再 edit sts ,把 partition 修改为 0
删除更新
只有删除 Pod 的时候才实现更新
[root@k8s-master1 ~]# kubectl edit sts web
updateStrategy:
#rollingUpdate:
# partition: 3
#type: RollingUpdate
type: OnDelete
# 修改镜像版本,删除 Pod, 查看是否只更新了删除后的Pod
级联删除和非级联删除
# 删除 statefulset 和 Headless Service
# 级联删除: 删除statefulset 时会同时删除 pods
kubectl delete statefulset web
kubectl delete svc nginx
# 非级联删除: 删除statefulset 时不会删除 pods, 删除sts盾,pod :
kubect1 delete sts web --cascade-false
删除PVC
# statefulset删除層PVC还会保留响,效摇不再使用的增也得要删除
kubectl delete pvc www-web-0 ww-web-1
DaemonSet 守护进程
为每一个匹配的Node都部署-一个守护进程
配置文件
[root@k8s-master1 ~]# kubectl label no k8s-node1 type=microservices # 添加一个标签,让守护进程在此标签下运行
node/k8s-node1 labeled
# daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
app: logging
template:
metadata:
labels:
app: logging
id: fluentd
name: fluentd
spec:
nodeSelector:
type: microservices
containers:
- name: fluentd-es
image: agilestacks/fluentd-elasticsearch:v1.3.0
env: #env:#环境变量配肾
- name: FLUENTD_ARGS # 环境变量的key
value: "-qq" # 环境变量的value
volumeMounts: # 加载数据卷,避免数据丢失
- name: containers # 数据卷的名字
mountPath: /var/lib/docker/containers # 将数据卷挂载到容器内的哪个日录
- name: varlog
mountPath: /varlog
volumes: # 定义数据卷
- hostPath: # 数据卷类型,主机路径的模式,也就是与node共享目录
path: /var/lib/docker/containers # node 中的共享目录
name: containers # 定义的数据卷的名称
- hostPath:
path: /var/log
name: varlog
[root@k8s-master1 ~]# kubectl create -f daemonset.yaml
daemonset.apps/fluentd created
[root@k8s-master1 ~]# kubectl get ds -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
fluentd 1 1 1 1 1 type=microservices 4m54s fluentd-es agilestacks/fluentd-elasticsearch:v1.3.0 app=logging
[root@k8s-master1 ~]# kubectl get po app=logging -o wide # 只在 node 节点标签 type=microservices 上
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-tpsg5 1/1 Running 0 5m13s 10.244.36.94 k8s-node1 <none> <none>
滚动更新
只有删除的时候才更新
# 不建议使用RollingUpdate.建议使用OnDelete模式,这样避免频繁更新id
[root@k8s-master1 ~]# kubectl edit ds fluentd
updateStrategy:
type: OnDelete
HPA
Pod自动扩容: 可以根据CPU使用率或自定义指标(metrics)
●控制管理器每隔30s (可以通过-horizontal-pod-autoscaler-sync-period惨改)查询metrics的资源使用情况
●支持三种metrics类型
。预定义metrics (比如Pod的CPU) 以利用率的方式计算
。自定义的Pod metrics, 以原始值(raw value) 的方式计算
。自定义的object metrics
●支持两种metrics查询方式: Heapster和白定义的REST API
●支持多metrics
HPA 开启指标服务
# 下载metrics-server组件配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
# #修改镜像地址为国内的地址
sed -i 's#registry.k8s.io/metrics-server#registry.cn-hangzhou.aliyuncs.com/google_containers#g' metrics-server-components.yaml
# 修改容器的tls配置,不验证tls,在containers的args参数中增加 `--kubelet-insecure-tls` 参数
[root@k8s-master1 ~]# kubectl create -f metrics-server-components.yaml
[root@k8s-master1 ~]# kubectl get po -A |grep metrics
kube-system metrics-server-5d6946c85b-zhdfj 1/1 Running 0 117s
CPU、内存指标监控
实现cpu或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或** resources.requests.memory** 才可以,
可以配置当cpu/memory达到上述配置的百分比后进行扩容或缩容
创建一个HPA:流程:
1.先准备好一个有做资源限制的deployment、service
2.执行命令
kubectl autoscale deploy <deploy. name> --cpu-percent= 20 --min=2 --max=5
3.通过
kubectl get hpa
可以获取HPA信息
# 1.先准备-个好一个有做资源限制的deployment
[root@k8s-master1 ~]# cat nginx-demo.yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx
spec:
selector:
app: nginx-deploy
ports:
- port: 80
targetPort: 80
name: web
type: NodePort
---
apiVersion: apps/v1 # deployment api版本
kind: Deployment # 资源类型为deployment
metadata: # 元信息
labels: # 标签
app: nginx-deploy # 具体的 key: value配置形式
name: nginx-deploy # deployment的名字
namespace: default # 所在的命名空间
spec:
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
selector: # 选择器,用于找到匹配的RS
matchLabels: # 按照标签匹配
app: nginx-deploy # 匹配的标签
strategy: # 更新策略
rollingUpdate: # 滚动更新配HI
maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod模板
metadata: # pod 的元信息
labels: # pod的标签
app: nginx-deploy
spec: # pod期望信息
containers: # pod的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: Always # 重启策略
name: nginx # 容器名称
resources:
requests: # 最少需要多少资源
cpu: 100m # 限制cpu最少使用0.1个核心
memory: 128Mi # 限制内存最少使用128兆
limits: # 最多可以用多少资源
cpu: 200m # 限制cpu最多使用0.2个核心
memory: 256Mi # 限制最多使用256兆
restartPolicy: Always # 删除操作最多宽限多长时间■
# 2.执行命令 `kubectl autoscale deploy <deploy. name> --cpu-percent= 20 --min=2 --max=5`
[root@k8s-master1 ~]# kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
horizontalpodautoscaler.autoscaling/nginx-deploy autoscaled
# 3.通过`kubectl get hpa`可以获取HPA信息
[root@k8s-master1 ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deploy Deployment/nginx-deploy <unknown>/20% 2 5 2 111s
[root@k8s-master1 ~]# kubectl top pods
NAME CPU(cores) MEMORY(bytes)
nginx-deploy-bc96d8cd9-74ms5 0m 1Mi
nginx-deploy-bc96d8cd9-khc68 0m 1Mi
# 测试:找到对应服务的service, 编写循环测试脚本提升内存与cpu负载,可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看pods的打容情况
while true; do wget -q -O- http://<ip:port> > /dev/nul; done
# 查看pods资源使用情况
kubectl get pods
kubectl top pods
kubectl get hpa -w
kubectl get deploy -w
自定义 metrics
●控制管理器开启
-horizontal-pod-autoscaler-use-rest-clients
●控制管理器的--apiserver指向
API Server Aggregator
●在 API Server Aggregator 中注册自定义的metrics API
服务发布-services
配置与基础命令
# 配置详解
apiVersion: v1
kind: Service # 资源类型为Service
metadata:
name: nginx-svc # Service 名字
labels:
app: nginx # Service 自己本身的标签
spec:
selector: # 匹配哪些pod 会被该service 代理
app: nginx-deploy # 所有匹配到这些标签的pod 都可以通过该service 进行访问
ports: # 端口映射
- port: 80 # service自己的端口,在使用内网ip访问时使用
targetPort: 80 #日标pod 的端口
#nodePort: 32000 # 固定绑定到所有 node 的32000 端口上
name: web # 为端口起个名字
type: NodePort # 如果不指定 nodePort ,会随机启动一个端口 (30000~32767),映射到 ports 中的端口,该端口处直接绑定在 node 上的。且集群中的每一个node 都会绑定这个端口, 也可以用于将服务暴露给外部访间,但这种方式实际生产环境不推荐,效率低,而且Service 是四层负载
# 创建service
kubectl create -f nginx-sVc.yaml
# 查看service信息,通过service的cluster ip进行访问
kubectl get svc
# 查看pod信息,通过pod的ip进行访问
kubectl get po -owide
# 创建其他 pod 通过 service name进行访问(推荐)
kubectl exec -it busybox -- sh # busybox 是自己创建的临时 pod
curl htp://nginx-gvc
# 默认在当前 namespace 中访问,如果需要跨namespace访问pod,则在service name后面加上.<namespace>即可
curl http://nginx-svc.default
Service 访问外部服务
推荐方式(不需要经常改动,管理方便)
比如现有业务无感迁移, 无状态相关应用使用 deploy, 数据库相关的使用 service 代理外部服务,后期数据库迁移过来时,也容易修改,只需要更新 service 即可
实现方式:
1.编写 service 配置文件时,不指定 selector 属性
2.自己创建 endpoint
# nginx-svc-endpoint.yaml 使用 service 代理外部 IP 访问
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-external
labels:
app: nginx
spec:
ports:
- port: 80
targetPort: 80
name: web
type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx # 与 service 标签一致
name: nginx-svc-external # 与 service 名字一致
namespace: default # 与 service 一致
subsets:
- addresses:
- ip: <远程地址> # 代理转发的目标 ip 地址
ports: # 与 service 一致
- name: web
port: 80
protocol: TCP
# nginx-svc-domain.yaml 使用 service 代理外部 域名 访问
[root@k8s-master1 ~]# cat nginx-domain.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-domain
labels:
app: nginx-svc-domain
spec:
type: ExternalName
externalName: www.baidu.com
[root@k8s-master1 ~]# kubectl get svc -l app=nginx-svc-domain
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc-domain ExternalName <none> www.baidu.com <none> 41s
kubectl get svc, ep
常用类型
ClusterIP 集群内部使用
ExternalName 返回定义的 CNAME 别名, 可以配置为域名
NodePort
会在所有安装了kube-proxy 的节点都绑定一个端中, 此端口可以代理至对应的Pod,集群外部可以使用任意节点ip +NodePort的端口号访问到集群中对应Pod中的服务,当类型设置为NodePort后,可以在ports配置中增加nodePort配置指定端口,需要在下方的端口范團内,如果不指定会随机指定端口
端口范围: 30000~32767
端口范围配置在/ysteys/systey/kube-episevereservice
LoadBalancer 使用云服务商(阿里云、腾讯云等) 提供的负载均衡器服务
服务发布-Ingress
参考: https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/
安装 Ingress
安装 Helm
官网: https://helm.sh/
cd /opt/ && mkdir helm && cd helm/
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
tar fx helm-v3.2.3-linux-amd64.tar.gz
cp linux-amd64/helm /usr/bin/
[root@k8s-master1 helm]# which helm
/usr/bin/helm
[root@k8s-master1 helm]# helm version
version.BuildInfo{Version:"v3.2.3", GitCommit:"8f832046e258e2cb800894579b1b3b50c2d83492", GitTreeState:"clean", GoVersion:"go1.13.12"}
添加 Helm 仓库
# 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 查看仓库列表
helm repo list
# 搜索ingress-nginx
[root@k8s-master1 helm]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.7.1 1.8.1 Ingress controller for Kubernetes using NGINX a...
下载安装包
# 下载包
helm pull ingress-nginx/ingress-nginx
# 解压
tar fx ingress-nginx-4.7.1.tgz
cd ingress-nginx
配置参数
# 1. 修改 values.yaml 镜像地址:为国内镜像, 国外无需修改镜像
controller:
name: controller
image:
## Keep false as default for now!
chroot: false
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/nginx-ingress-controller
.... 并注释掉 Hash 校验值,因为修改了镜像地址,所以不需要校验
# digest: sha256:e5c4824e7375fcf2a393e1c03c293b69759af37a9ca6abdb91b13d78a93da8bd
# digestChroot: sha256:e0d4121e3c5e39de9122e55e331a32d5ebf8d4d257227cb93ab54a1b912a7627
... 搜索 kube-webhook 修改配置如下
patch:
enabled: true
image:
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/kube-webhook-certgen
tag: v1.5.1
## for backwards compatibility consider setting the full image url via the repository value below
## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
## repository:
#tag: v20230407
#digest: sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
#pullPolicy: IfNotPresent
# 2. 修改部署配置的 kind 为 DaemonSet, nodeSelector.ingress 为 true
# -- Use a `DaemonSet` or `Deployment`
kind: DaemonSet
nodeSelector:
kubernetes.io/os: linux
ingress: "true"
# 3. 修改其他参数
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
type: ClusterIP # 如果是云平台使用 LoadBalancer
admissionWebhooks:
...
enabled: false # 设置为 false,true 为https证书方式
创建 Namespace
kubectl create ns ingress-nginx
安装 ingress
# 为需要部署 ingress 的节点的加标签, 我们这里部署到 node1 商
kubectl label node k8s-node1 ingress=true
# 安装 ingress-nginx
helm install ingress-nginx -n ingress-nginx .
# 如果安装失败,先卸载,修改之后重新执行安装:helm uninstall ingress-nginx -n ingress-nginx
# 之后安装到 node1 节点,
[root@k8s-master1 ingress-nginx]# kubectl get po -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-94vcq 0/1 ContainerCreating 0 38s 192.168.8.129 k8s-node1 <none> <none>
路径匹配和虚拟主机配置
多域名配置: rules 下面多复制几分,修改下 域名即可
[root@k8s-master1 ~]# kubectl get svc |grep nginx-svc # 目前已经有一个 svc
nginx-svc NodePort 10.103.189.179 <none> 80:32572/TCP 9h
[root@k8s-master1 ~]# cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nignx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # Ingress 规则配置,可以配置多个
- host: kk8s.wolfcode.cn #域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的location 配置,可以配置多个
- pathType: Prefix # 路径类型,安装路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass, 具体匹配规则以 IngressClass 中的规则为准。 Exact: 精确匹配, URL 需要与path完全匹配上,且区分大小写。 Prefix: 以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # services 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配,可正则,和nginx相同
[root@k8s-master1 ~]# kubectl create -f ingress.yaml
ingress.networking.k8s.io/wolfcode-nginx-ingress created
[root@k8s-master1 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
wolfcode-nginx-ingress <none> kk8s.wolfcode.cn 80 2m54s
[root@k8s-master1 ~]# kubectl get po -n ingress-nginx -o wide # 反向只有 node1 节点上创建了 pod
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-94vcq 1/1 Running 0 24m 192.168.8.129 k8s-node1 <none> <none>
[root@k8s-master1 ~]# helm ls -A
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
ingress-nginx ingress-nginx 1 2023-07-03 19:44:08.059637001 +0800 CST deployed ingress-nginx-4.7.1 1.8.1
# 如果修改了配置文件,使用替换方式重新部署
kubectl replace -f ingress.yaml
curl http://kk8s.wolfcode.cn/api/index.html
配置与存储
ConfigMap
ConfigMap 创建
# 帮助
kubectl create cm -h
Examples:
# Create a new config map named my-config based on folder bar
kubectl create configmap my-config --from-file=path/to/bar
# Create a new config map named my-config with specified keys instead of file basenames on disk
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
# Create a new config map named my-config with key1=config1 and key2=config2
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
# Create a new config map named my-config from the key=value pairs in the file
kubectl create configmap my-config --from-file=path/to/bar
# Create a new config map named my-config from an env file
kubectl create configmap my-config --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env
# 文件内容, k: v形式、k=v形式、 yaml 格式
ConfigMap 使用和加载
[root@k8s-master1 ~]# kubectl create configmap test-env-config --from-literal=JAVA_OPTS_TEST=11111 --from-literal=APP_NAME=222222
configmap/test-env-config created
[root@k8s-master1 ~]# more test-cm-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env-cm
spec:
restartPolicy: Never
containers:
- name: env-test
image: alpine
command: ["/bin/sh", "-c", "env; sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config # configMap 的名字
key: JAVA_OPTS_TEST # 表示从 name 的 ConfigMap 中获取名字为 key 的 value, 将其赋值给本地环境变量 JAVA_VM_OPTS
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
## 测试变量是否加载到容器内
[root@k8s-master1 ~]# kubectl logs -f test-env-cm |grep -E "111|222"
JAVA_VM_OPTS=11111
APP=222222
热更新
[root@k8s-master1 ~]# cat auto-cm-reload.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-nginx
spec:
replicas: 1
selector:
matchLabels:
run: test-nginx
template:
metadata:
labels:
run: test-nginx
spec:
containers:
- name: test-nginx
image: nginx:1.7.9
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: log-config
# 查看当前挂载内容
kubectl exec test-nginx-7f9db59dcd-8v2zc -it -- sh -c "cat /etc/config/log_level"
# 修改 INFO 为 DEBUG
[root@k8s-master1 ~]# kubectl edit cm log-config
configmap/log-config edited
# 等待大概 10 秒钟时间,再次查看环境变量的值
[root@k8s-master1 ~]# kubectl exec test-nginx-7f9db59dcd-8v2zc -it -- sh -c "cat /etc/config/log_level"
DEBUG
ConfigMap 更新后滚动更新 Pod
# 更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新
kubectl patch deployment test-nginx --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20190411" }}}}}'
Secret
# 命令帮助
kubectl create secret -h
Service Account
用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到
Pod
的
[root@k8s-master1 ~]# kubectl exec <pod_name> -- sh -c "ls /run/secrets/kubernetes.io/serviceaccount"
ca.crt
namespace
token
Opaque
map
类型,要求value
是base64
编码格式:
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
secrets.yml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
# 将 Secret 挂载到 Volume 中
apiVersion: v1
kind: Pod
metadata:
labels:
name: seret-test
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- image: hub.atguigu.com/library/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/myapp"
readOnly: true
# 将 Secret 导出到环境变量中
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-deployment
spec:
replicas: 2
selector:
matchLabels:
app: pod-deployment
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: nginx:1.7.9
env:
- name: TEST_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
kubernetes.io/dockerconfigjson
kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret "myregistrykey" created
# 在创建 `Pod` 的时候,通过 `imagePullSecrets` 来引用刚创建的 `myregistrykey`
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: nginx:1.7.9
imagePullSecrets:
- name: myregistrykey
持久化存储
Volumes-HostPath
将节点上的文件或目录挂载到Pod上,此时该目录会变成持久化存储目录,即使Pod被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失
空字符串(默认) 默认类型,不做任何检查
DirectoryOrCreate 如果在给定的路径上不存在,则创建一个空目录,权限 0755
Directory 目录,必须存在。
FileOrCreate 如果在给定的路径上不存在,则创建一个空文件,权限设 0644
File 必须存在文件。
Socket UNIX 套接字,必须存在 。
CharDevice 字符设备,必须存在
BlockDevice 块设备,必须存在
apiVersion: v1
kind: Pod
metadata:
name: test-volume-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd # 挂载到容器的哪个目录
name: test-volume # 挂载哪个volume
volumes:
- name: test-volume
hostPath:
path: /data # 与主机共享目录,加载主机中的指定目录到容器中
type: Directory # 检查类型,在挂载前对挂载目录做什么检查操作,有多种谐项,默认为空字符串,不做任何检在
Volumes-EmptyDir
EmptyDir主要用于一个Pod中不同的Container共享数据使用的,由于只是在Pod内部使用,因此与其他volume比较大的区别是,当Pod如果被删除了,那么emptyDir也会被删除。
存储介质可以是任意类型,如SSD、磁盘或网络存储。可以将 emptyDir.medkam 设置为Memory让k8s使用tmpfs (内存支持文件系统),速度比较快,但是重启tmpfs节点时,数据会被清除,且设置的大小会计入到Container的内存限制中。
# 测试一个 Pod 两个容器
[root@k8s-master1 ~]# cat test-volume-emtry.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: alpine
name: test-empty1
command: ["/bin/sh", "-c", "sleep 3600;"]
volumeMounts:
- mountPath: /cache
name: cache-volume
- image: alpine
name: test-empty2
command: ["/bin/sh", "-c", "sleep 3600;"]
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
[root@k8s-master1 ~]# kubectl create -f test-volume-emtry.yaml
pod/test-pd created
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
test-pd 2/2 Running 0 53s
# 开两个终端,测试两个容器数据是否共享
[root@k8s-master1 ~]# kubectl exec -it test-pd -c test-empty1 -- sh
[root@k8s-master1 ~]# kubectl exec -it test-pd -c test-empty2 -- sh
NFS 挂载
安装 NFS
# 安装 nfs,所有节点安装
yum install nfs-utils -y
# 启动 nfs,所有节点启动
systemctl start nfs-server
# 查看 nfs 版本
cat /proc/fs/nfsd/versions
# NFS节点创建共享目录, ro 只读共享目录, rw 读写共享目录
mkdir -p /home/nfs/{ro, rw}
# NFS节点设置共享目录 export
vim /etc/exports
/home/nfs/ro xx.xx.xx.0/24(ro,sync,no_subtree_check,no_root_squash) /home/nfs/ro
/home/nfs/rw xx.xx.xx.0/24(rw,sync,no_subtree_check,no_root_squash) /home/nfs/rw
# NFS节点重新加载
exportfs -f
systemctl reload nfs-server
# 到其他节点安装 nfs-utils 并加载测试
mkdir -p /mnt/nfs/{ro,rw}
mount -t nfs nfs:/home/nfs/rw /mnt/nfs/rw
mount -t nfs nfs:/home/nfs/ro /mnt/nfs/ro
如何使用
创建两个测试的 pod, 测试 nfs 挂载目录文件
[root@k8s-master1 ~]# cat test-nfs-pd1.yaml
apiVersion: v1
kind: Pod
metadata:
name: nfs-test-pd1
spec:
containers:
- image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
nfs:
server: 192.168.8.131 # 网络存储服务地址
path: /home/nfs/rw/www/wolfcode # 网络存储路径
readOnly: false # 是否只读
动态 StorageClass
参考: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
# NFS 服务
[root@k8s-master2 nfs]# cat /etc/exports
/home/nfs/dynamic 192.168.8.0/24(rw,sync,no_subtree_check,no_root_squash) /home/nfs/dynamic
[root@k8s-master1 ~]# showmount -e 192.168.8.131
Export list for 192.168.8.131:
/home/nfs/dynamic 192.168.8.0/24
# 部署动态 sc
[root@k8s-master1 ~]# helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
[root@k8s-master1 ~]# helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.8.131 \
--set nfs.path=/home/nfs/dynamic \
--set storageClass.name=managed-nfs-storage
[root@k8s-master1 ~]# kubectl get sc,deploy
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
storageclass.storage.k8s.io/managed-nfs-storage cluster.local/nfs-subdir-external-provisioner Delete Immediate true 13m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nfs-subdir-external-provisioner 1/1 1 1 13m
PV与PVC
生命周期
构建
1.1 静态构建
集群管理员创建若干PV卷。这些卷对象带有真实存储的细节信息,并且对集群用户可用(可见)。卷对象存在于Kubernetes API中,可供用户消费(使用)
1.2 动态构建
如果集群中已经有的PV无法满足PVC的需求,那么集群会根据PVC自动构建-个PV,该操作是通过StorageClass实现的。
想要实现这个操作,前提是PVC必须设置StorageClass,否则会无法动态构建该PV,可以通过启用DefaultStorageClass来实现PV的构建。
绑定
当用户创建一个PVC对象后,主节点会监测新的PVC对象,并且寻找与之匹配的PV卷,找到PV卷后将二者绑定在一起。
如果找不到对应的PV,则需要看PVC是否设置StorageClass来决定是否动态创建PV,若没有配置,PVC 就会致处于未绑定状态,直到有与之匹配的bV后才会申领绑定关系。
使用
Pod将PVC当作存储卷来使用,集群会通过PVC找到绑定的PV,并为Pod挂载该卷。Pod - -旦使用PVC绑定PV后,为了保护数据,避免数据丢失问题,PV 对象会受到保护,在系统中无法被删除。
回收策略
当用户不再使用其存储卷时,他们可以从API中将PVC对象删除,从而允许该资源被回收再利用。 PersistentVolume 对象的回收策略告诉集群,当其被从申领中释放时如何处理该数据卷。 目前,數据卷可以被
Retained
(保留)、Recycred
(回收)或Deleted
(删除)。
Retained(保留)
回收策略Retain 使得用户可以手动回收资源。当PersistentVolumeClaim对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为“已释放(released) ”.由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他用领。管理员可以通过下面的步骤来手动回收该卷:
- 1.删除PersistentVolume对象。与之相关的、位于外部基础设施中的存储资产(例如 AWS EBS、GCE PD、Azure Disk或Cinder卷)在PV删除之后仍然存在,
- 2.根据情况,手动清除所关联的存储资产上的数据,
- 3.手动删除所关联的存储资产。
Deleted删除
对于支持Delete回收策略的卷插件,删除动作会将PersistentVolume对象以Kubernetes中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk或Cinder卷)中移除所关联的存储资产。动态制备的卷 会继承其StorageClass中设置的回收策略,该策略默认为 Delete.管理员需要根据用户的期望来配置StorageClass;否则PV卷被创建之后必须要被编辑或者修补。
Recycred回收
警告:回收策略Recycle已被废弃。取而代之的建议方案是使用动态制备。 如果下层的卷播件支持,回收策鰭Recycle会在卷上执行-些基本的擦除(rm -rf /thevolume/")操作,之后允许该卷用于新的PVC申领。
PV
状态
Available: 空闲,未被绑定
Bound: 已经被 PVC 绑定
Released: PVC 被删除,资源已回收,但是 PV 未被重新使用
Failed: 自动回收失败
配置文件
apiVersion: v1
kind: PersistentVolume # 描述资源对象为 PV 类型
metadata:
name: nfs-pv # PV 的名字
spec:
capacity: # 容量配置
storage: 1Gi # PV 的容量
accessModes: # 访间模式: ReadWriteOnce、ReadWriteMany、ReadOnlyMany
- ReadWriteMany # 可被单节点独写
persistentVolumeReclaimPolicy: Recycle # 回收策略
volumeMode: Filesystem # 存储学型为文件系统
storageClassName: slow # 创建PV的存储类名,需要与 pvc 的相同
mountOptions: # 加载配置
- hard
- nfsvers=4.1
nfs: # 链接到 nfs
path: /home/nfs/ro/test-pv # 存储路径
server: 192.168.8.131 # nfs 服务地址
PVC
apiVersion: v1
kind: PersistentVolumeClaim # 资源类型为 PVC
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany # 权限需要与对应的 PV 相同
volumeMode: Filesystem
resources:
requests:
storage: 1Gi # 资源小于 pv,不能大于,如果大于无法匹配到 pv
storageClassName: slow # 名字需要与对应的 pv 相同
# selector: # 使用选择器选择对应的 pv
# matchLabels:
# release: "stable"
# matchExpressions:
# - {key: environment, operator: In, values: [dev]}
测试PV与PVC
apiVersion: v1
kind: Pod
metadata:
name: test-pvc-pd
spec:
containers:
- image: nginx
name: nginx-volume
volumeMounts:
- mountPath: /usr/share/nginx/html # 挂载到容器的哪个目录
name: test-volume # 挂载哪个 volume
volumes:
- name: test-volume
persistentVolumeClaim: # 关联 pvc
claimName: nfs-pvc # 要关联到哪个 pvc
StorageClass动态
制备器
NFS 动态支部案例
nfs-provisioner
StorageClass配置
RBAC配置
PVC处于Pending状态
PVC测试配置
高级调度
CronJob 计划任务
在k8s中周期性运行计划任价与linux中的crontab相同 注意点: CronJob 执行的时间是controller-manager的时间,所以定要确保contrller-manager时间是准确的,另外cronjob
配置文件
应该是: successfulJobsHistoryLimit
kubectl get cj
初始化容器
initContainers: # 和 containers 同级,spec.initContainers
- image: nginx
imagePullOolicy: IfNotPresent
command: ["sh", "-c", "sleep 10; echo 'inited'; >> ~/.init"]
name: init-test
containers:
...
...
污点和容忍
污点
NoSchedule: 节点污点,无法被调度到此,已存在pod不受影响
NoExecute: 驱逐Pod,调用到其他节点
容忍
Equal: 容忍和污点对比, key、value 必须相同才可以调度
Exists: 容忍和污点只对比 key,key存在则容忍
3。 污点驱逐类型
node.kubernetes.io/not-ready:节点未准备好。这相当于节点状况 Ready 的值为 "False"。
node.kubernetes.io/unreachable:节点控制器访问不到节点. 这相当于节点状况 Ready 的值为 "Unknown"。
node.kubernetes.io/memory-pressure:节点存在内存压力。
node.kubernetes.io/disk-pressure:节点存在磁盘压力。
node.kubernetes.io/pid-pressure: 节点的 PID 压力。
node.kubernetes.io/network-unavailable:节点网络不可用。
node.kubernetes.io/unschedulable: 节点不可调度。
node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个“外部”云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
污点:是标注在节点上的,当我们在一个节点 上打上污点以后,k8s会认为尽量不要将pod调度到该节点上,除非该pod上面表示可以容忍该污点,且-个节点可以打多个污点,此时则需要pod容忍所有污点才会被调度该节点。
# 为节点打上污点
kubectl taint no k8s-master key1=value1:NoSchedule
# 移除污点
kubectl taint no k8s-master key1=value1:NoSchedule-
场景一
# 与 container 同级
tolerations:
- key: "key1" # key 值
operator: "Equal" # 容忍类型,key、value 必须相同才可以调度
value: "value1" # value 值
effect: "NoSchedule" # 污点类型
场景二
tolerations:
- key: "key1" # Key 值
operator: "Exists" # 容忍类型。key存在则容忍
effect: "NoSchedule" # 污点类型
场景三
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600 # 延迟驱逐
亲和力和反亲和力
详情查看官网: https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/
Node 亲和性 || Pod 亲和性
requiredDuringSchedulingIgnoredDuringExecution 硬亲和性, 规则被满足的时候才能执行调度
preferredDuringSchedulingIgnoredDuringExecution 软(反)亲和性,如果没有匹配规则节点,则可以继续调度
例如: 混合云机房
身份认证与权限
认证
User Account 普通账户
Service Accounts 服务账户
Service Account Adminision Controller
Token Controller
Service Account Controller
授权
Role (命名空间级别)
代表一个角色,会包含-组权限, 没有拒绝规则,只是附加允许。它是Namespace级别的资源,只能作用与Namespace之内。
ClusterRole (集群空间级别)
RoleBinding
ClusterRoleBinding
kubectl get sa # 查看认证账户
# 查看已有命名空间角色信息
kubectl get role -A
# 查看已有已有集群空间角色信息
kubectl get clusterrole
# 查看 rolebinding 信息
kubectl get rolebinding -A
# 查看指定 rolebinding 配置信息
kubect get rolebinding <role_binding_name> -A -o yaml
Helm 包管理器
管理 chart、config、release
安装
参考安装: ingress-nginx 部分
Helm 常用命令
helm version # 查看helm版本
helm create xxx # 创建一个xxx charts
helm lint ./xxx # 检查包的格式或信息是否有问题
helm install xxx1 ./xxx # 部署安装xxx,设置名称为xxx1
helm list # 列出已经部署的charts
helm history # 发布历史
helm upgrade # 更新版本
helm rollback # 回滚版本
helm package ./xxx # 打包charts
helm repo add --username admin --password password myharbor xxx # 增加repo
helm uninstall xxx1 # 卸载删除xxx1
helm pull # 拉取chart包
helm cm-push # 推送chart包
helm repo update # 更新仓库资源
helm search hub # 从 Artifact Hub 中查找并列出 helm charts。 Artifact Hub中存放了大量不同的仓库
helm search repo # 从你添加(使用 helm repo add)到本地 helm
helm dependency # 管理 chart 依赖
Helm 目录结构
mycahrt/
├── Chart.yaml # chart 描述信息
├── values.yaml # 定义 chart 模板中自定义配置默认值,可以在外部执行覆盖
├── charts/ # 该目录保存其他依赖的 chart (子chart)
└── templates/ # chart 配置模板,用户渲染最终的 kubernets YAML
└── NOTES.TEXT # 用于运行 helm install 时候提示信息
└── _helpers.tpl # 用于创建模板的帮助类
└── deployment.yaml # Kubernetes deployment 配置
└── ingress.yaml # Kubernetes ingress 配置
└── service.yaml # Kubernetes service 配置
└── ingress.yaml # Kubernetes ingress 配置
└── serviceaccount.yaml # Kubernetes serviceaccount 配置
└── tests
└── test-connection.yaml
Helm 实践 Redis chart
需要动态storageclasses: (managed-nfs-storage)名字
3主3从
修改 helm 源
# 查看默认仓库
helm repo list
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add azure http://mirror.azure.cn/kubernetes/charts
搜索 redis chart
helm search repo redis
# 查看指定 chart 文档
helm show readme <serach_name>
传变量在线安装
已经设置了 nfs 为默认存储, 那这里就不需要 存储参数了
helm install redis-cluster bitnami/redis-cluster \
--set global.redis.password=123456 -n saas
修改配置安装
[root@k8s-master1 ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage cluster.local/nfs-subdir-external-provisioner Delete Immediate true 165m
# 先将 chart 拉到本地
helm pull bitnami/redis-cluster --version 8.6.6
# 解压后,修改 values.yaml 中参数
tar -xvf redis-cluster-8.6.6.tgz
cp redis-cluster/values.yaml ./redis-cluster-values.yaml
# 修改 storageClass 为 managed-nfs-storage
# 设置 redis 密码 password
# 设置 运行在 中间件 节点上
global:
imageRegistry: ""
imagePullSecrets: []
storageClass: "managed-nfs-storage" # nfs 持久化存储名字
redis:
password: "123456"
password: "123456"
`nodeSelector`: {"node":"middleware"} # 设置了服务的 node 亲和性,确保服务运行在指定的节点 (部分 k8s-node 节点运行中间件,部分 k8s-node 节点运行业务)
updateJob:
nodeSelector: {"node":"middleware"} # 设置了服务的 node 亲和性,确保服务运行在指定的节点 (部分 k8s-node 节点运行中间件,部分 k8s-node 节点运行业务)
# 安装操作
kubectl create ns redis
# 安装, helm 名字 redis-cluster , 镜像 bitnami/redis-cluster, 版本 8.6.6, 空间 redis, 变量文件
helm install redis-cluster bitnami/redis-cluster -f redis-cluster-values.yaml -n redis
查看安装情况
helm list -n redis
kubectl get all -n redis
kubectl get sc
连接
Redis 集群
验证服务
# 获取内部 dns 域名
[root@k8s-master1 ~]# kubectl describe po redis-cluster-4 -n redis |grep REDIS_NODES
REDIS_NODES: redis-cluster-0.redis-cluster-headless redis-cluster-1.redis-cluster-headless redis-cluster-2.redis-cluster-headless redis-cluster-3.redis-cluster-headless redis-cluster-4.redis-cluster-headless redis-cluster-5.redis-cluster-headless
# 进入临时终端
kubectl run --namespace redis redis-cluster-client --rm --tty -i --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image bitnami/redis-cluster:7.0.11-debian-11-r27 -- bash
# 登录redis集群测试
redis-cli -c -h redis-cluster-1.redis-cluster-headless -a $REDIS_PASSWORD
# 查看集群状态
> cluster info
> cluster nodes
提供服务给外部
[root@k8s-master1 ~]# kubectl get svc -n redis
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-cluster ClusterIP 10.108.84.182 <none> 6379/TCP 101m
redis-cluster-headless ClusterIP None <none> 6379/TCP,16379/TCP 101m
# kubernetes 内部应用只需要链接 <server_name>:<port> 既可通信
redis-cluster:6379
升级与回滚
# 升级
helm upgrade [release] [chart] [flags]
helm upgrade redis-cluster bitnami/redis-cluster -f redis-cluster-values.yaml -n redis
# 回滚到历史版本
helm ls
helm rollback <release> [revision] [flags]
# 查看历史
helm history redis-cluster
# 回退到上一个版本
helm rollback redis-cluster
# 回退到指定版本
helm rollback redis-cluster <version>
helm 卸载 redis
helm delete redis -n redis
Helm 实践 kube-prometheus-stack
动态存储: 如何创建, 查看 动态NFS StorageClass 步骤
方法一: Helm 方式安装(推荐)
参考: kube-prometheus-stack安装及使用 - 墨天轮 (modb.pro) 参考: 一文搞懂基于 Helm 部署 Prometheus Stack 全家桶 - Luga Lee - twt企业IT交流平台 (talkwithtrend.com) 参考: prometheus-operator/kube-prometheus: Use Prometheus to monitor Kubernetes and applications running on Kubernetes (github.com)
# 创建命名空间
kubectl create ns kube-monitor
# 添加helm仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# 更新仓库
helm repo update
# 安装 kube-prometheus-stack, 我 k8s 版本 1.23.6 ,这里我使用默认最新,如果其他版本例如: --version 45.0.0
helm search repo prometheus-communit -l |grep prometheus-stack
helm pull prometheus-community/kube-prometheus-stack
修改values.yaml,将storageClassName值替换为创建的managed-nfs-storage
# 备份
[root@ecs-6272 ~]# helm show values prometheus-community/kube-prometheus-stack > /tmp/values.yaml # 备份一下
# prometheus、alertmanager 存储
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: managed-nfs-storage
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 1Gi
存在则更新
# 如果没有,则部署新的
helm install prometheus-community/kube-prometheus-stack -n kube-monitor -f values.yaml
# 如果已经部署了,修改完配置用 helm upgrade 更新配置。
[root@ecs-6272 ~]# helm upgrade --install prometheus prometheus-community/kube-prometheus-stack -n kube-monitor -f values.yaml # 更新配置
检查
# 查看是否都是 running
[root@k8s-master1 ~]# kubectl get pod -n kube-monitor
# 查看 pv 和 pvc 是否持久化
[root@k8s-master1 ~]# kubectl get pv,pvc
使用 Ingress 提供服务
# 使用 Ingress 提供服务
[root@k8s-master1 ~]# kubectl get svc -n kube-monitor
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus-grafana ClusterIP 10.103.87.103 <none> 80/TCP 114m
prometheus-kube-prometheus-alertmanager ClusterIP 10.97.106.233 <none> 9093/TCP,8080/TCP 114m
prometheus-kube-prometheus-prometheus ClusterIP 10.107.45.13 <none> 9090/TCP,8080/TCP 114m
...略
[root@k8s-master1 ~]# cat kube-prometheus-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: kube-monitor # Prometheus 自定义命名空间
name: prometheus-ingress
spec:
ingressClassName: nginx
rules:
- host: grafana.kube.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: prometheus-grafana
port:
number: 80
- host: prometheus.kube.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: prometheus-kube-prometheus-prometheus
port:
number: 9090
- host: altermanager.kube.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: prometheus-kube-prometheus-alertmanager
port:
number: 9093
[root@k8s-master1 ~]# kubectl create -f ./kube-prometheus-ingress.yaml
# grafana 默认账号密码为 admin | prom-operator
方法二: Yaml 方式安装
git clone https://github.com/prometheus-operator/kube-prometheus.git -b release-0.10
# 修改下 values.yaml 配置
# 1、
kubectl create -f manifests/setup
# 2、
kubectl apply -f manifests/
# 查看
kubectl get all -n monitoring
kubectl get pods -n monitoring -o wide
# 如果出现错误,定位错误修复
kubecl describe pod [pod_name] -n [namespace]
Helm 实战 RadonDB MySQL Operator 集群
官网: https://radondb.com/ 备份: 查看官网
# 添加 Helm 仓库 radondb 。
helm repo add radondb https://radondb.github.io/radondb-mysql-kubernetes/
helm search repo mysql-operator
# 部署 Operator, 名字为 mysql
kubectl create ns mysql-cluster
helm install mysql radondb/mysql-operator -n mysql-cluster
# 部署 RadonDB MySQL 集群, 使用默认参数为 CRD mysqlclusters.mysql.radondb.com 创建一个实例,即创建 RadonDB MySQL 集群。
[root@k8s-master1 ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage cluster.local/nfs-subdir-external-provisioner Delete Immediate true 29h
[root@k8s-master1 ~]# wget https://github.com/radondb/radondb-mysql-kubernetes/releases/latest/download/mysql_v1alpha1_mysqlcluster.yaml
# 修改 mysql_v1alpha1_mysqlcluster.yaml 持久化存储, storageClass: "managed-nfs-storage"
[root@k8s-master1 ~]# kubectl apply -f ./mysql_v1alpha1_mysqlcluster.yaml -n mysql-cluster
# 校验 RadonDB MySQL Operator
[root@k8s-master1 ~]# kubectl get deployment,svc -n mysql-cluster
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/mysql-mysql-operator 1/1 1 1 12m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mysql-operator-metrics ClusterIP 10.109.127.112 <none> 8443/TCP 12m
service/radondb-mysql-webhook ClusterIP 10.111.183.95 <none> 443/TCP 12m
# 校验 RadonDB MySQL 集群
[root@k8s-master1 ~]# kubectl get crd -n mysql-cluster| grep mysql.radondb.com
backups.mysql.radondb.com 2023-07-07T14:36:36Z
mysqlclusters.mysql.radondb.com 2023-07-07T14:36:36Z
mysqlusers.mysql.radondb.com 2023-07-07T14:36:36Z
[root@k8s-master1 ~]# kubectl get po -n mysql-cluster
NAME READY STATUS RESTARTS AGE
mysql-mysql-operator-6f7686dc46-kq7p8 2/2 Running 2 (11m ago) 38m
sample-mysql-0 3/3 Running 0 15m
sample-mysql-1 3/3 Running 0 5m21s
sample-mysql-2 3/3 Running 0 2m9s
** 访问集群**
在 Kubernetes 集群内,支持使用 service_name 或者 clusterIP 方式,访问 RadonDB MySQL。 RadonDB MySQL 提供 Leader 和 Follower 两种服务,分别用于客户端访问主从节点。Leader 服务始终指向主节点(可读写),Follower 服务始终指向从节点(只读)。
# ClusterIP 方式
RadonDB MySQL 的高可用读写 IP 指向 Leader 服务的 clusterIP,高可用只读 IP 指向 Follower 服务的 clusterIP。
mysql -h <clusterIP> -P <mysql_Port> -u <user_name> -p
# 以下示例用户名为 radondb_usr, Leader 服务的 clusterIP 为 10.10.128.136 ,连接示例如下:
mysql -h 10.10.128.136 -P 3306 -u radondb_usr -p
# service_name 方式
Kubernetes 集群的 Pod 之间支持通过 service_name 方式访问 RadonDB MySQL。
service_name 方式不适用于从 Kubernetes 集群的物理机访问数据库 Pod。
连接 Leader 服务(RadonDB MySQL 主节点)
mysql -h <leader_service_name>.<namespace> -u <user_name> -p
用户名为 radondb_usr,release 名为 sample,RadonDB MySQL 命名空间为 default ,连接示例如下:
mysql -h sample-leader.default -u radondb_usr -p
连接 Follower 服务(RadonDB MySQL 从节点)
mysql -h <follower_service_name>.<namespace> -u <user_name> -p
用户名为 radondb_usr,release 名为 sample,RadonDB MySQL 命名空间
为 default ,连接示例如下:
mysql -h sample-follower.default -u radondb_usr -p
卸载
# 卸载 Operator
卸载当前命名空间下 release 名为 demo 的 RadonDB MySQL Operator。
helm delete demo
# 卸载集群
卸载 release 名为 sample RadonDB MySQL 集群。
kubectl delete mysqlclusters.mysql.radondb.com sample
# 卸载自定义资源
kubectl delete customresourcedefinitions.apiextensions.k8s.io mysqlclusters.mysql.radondb.com
kubectl delete customresourcedefinitions.apiextensions.k8s.io mysqlusers.mysql.radondb.com
kubectl delete customresourcedefinitions.apiextensions.k8s.io backups.mysql.radondb.com
k8s 删除 ns、pod 卡住的解决办法
在某些情况下,在k8s中会无法删除某个namespace,它会一直卡在terminating状态下。解决这个问题的步骤为:
# 这个指令找到阻碍这个namespace删除的资源,
kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n <namespace>
# 然后手动删除这些 Pod 资源。
kubectl delete pod xxx -n xxxx --force
# 或者 `kubectl edit pod -o json` 然后找到里面的"finalizers",把它的值设置成一个空数组。
但是大部分时候,这些资源也杀不掉,解决办法是执行
kubectl edit pod -o json
然后找到里面的"finalizers",把它的值设置成一个空数组。
解决这些资源后,参照以下文档删除那个ns:
Last updated