kubernetes 学习笔记

1. Kubernetes 介绍

1.1 应用部署方式的演变

在部署应用程序的方式上,主要经理了三个时代:

  • 传统部署:互联网早期,会直接将应用程序部署在物理机上。
  • 虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是一个独立的环境。
  • 容器化部署:与虚拟化类似,但是共享了操作系统。

容器化部署方式带来的问题:

  • 一个容器故障停机了,怎么样让另外一个容器立刻启动去替补停机的容器。
  • 当并发访问量变大的时候,怎么样做到横向扩展容器数量。

容器管理的问题通常称为容器编排问题,为了解决这些容器编排问题,就产生了一些容器编排的软件。

  • Swarm: Docker 自己的容器编排工具。
  • Mesos:Apache 的一个资源统一管控的工具,需要和 Marathon 结合使用。
  • Kubernetes:Google 开源的容器编排工具。

1.2 Kubernetes 简介

kubernetes 是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器 Borg 系统的一个开源版本,于 2014 年 9 月发布第一个版本,2015年7月发布第一个正式版本。

kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。它的目的就是实现资源管理的自动化,主要提供了如下的主要功能:

  • 自我修复:一旦某一个容器奔溃,能够在1秒中左右迅速启动新的容器。
  • 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整。
  • 服务发现:服务可以通过自动发现的形式找到它所依赖的服务。
  • 负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡。
  • 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本。
  • 存储编排:可以根据容器自身的需求自动创建存储卷。

1.3 kubernetes 组件

一个 kubernetes 集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。

master:集群的控制平面,负责集群的决策。

  • ApiServer:资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制。
  • Schedule:负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上。
  • ControllerManager:负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等。
  • Etcd:负责存储集群中各种资源对象的信息。

node:集群的数据平面,负责为容器提供运行环境。

  • kubelet:负责维护容器的生命周期,即通过控制 docker,来创建、更新、销毁容器。
  • kubeProxy:负责提供集群内部的服务发现和负载均衡。
  • Docker:负责节点上容器的各种操作。
    Kubernetes组件

下面,以部署一个 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 是 kubenetes 的最小操作单元,容器必须跑在 Pod 中至此。
  6. 一个 nginx 服务就运行了,如果需要访问 nginx,就需要通过 kube-proxy 来对 pod 产生访问的代理这样,外界用户就可以访问集群中的 nginx 服务了。

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 会拥有相同的标签。
NameSpace: 命名空间,用来隔离 pod 的运行环境。

2. Kubernetes 集群环境搭建

2.1 环境规划

2.1.1 集群类型

集群类型:kubernetes 集群大体上分为两类,一主多从和多主多从。

  • 一主多从:一台 Master 节点和多台 Node 节点,搭建简单,但是有单机故障风险。适合用于测试环境。
  • 多主多从:多台 Master 节点和多台 Node 节点,搭建麻烦,安全性高,适合用于生产环境。

kubernetes集群类型

说明:为了测试简单,本次搭建的是 一主两从 类型的集群

2.1.2 安装方式

kubernetes 有多种部署方式,目前主流的方式有

  • minikube:一个用于快速搭建单节点 kubernetes 的工具。
  • kubeadm:一个用于快速搭建 kubernetes 集群的工具。
  • 二进制包:从官网下载每个组件的二进制包,依次去安装,此方式对于理解 kubernetes 组件更加有效。

说明:现在需要安装 kubernetes 的集群环境,但是又不想过于麻烦,所以选择使用 kubeadm 方式。

2.1.3 主机规划

作用IP地址操作系统配置
Master192.168.3.53Centos7 基础设施服务器2颗CPU、2G内存、50G硬盘
Node1192.168.3.54Centos7 基础设施服务器2颗CPU、2G内存、50G硬盘
Node2192.168.3.55Centos7 基础设施服务器2颗CPU、2G内存、50G硬盘

2.2 环境搭建

本次环境搭建需要安装三台 Centos 服务器 (一主二从),然后在每台服务器中分别安装 docker(18.06.3)、kubeadm(1.17.4)、kubelet(1.17.4)、kubectl(1.17.4) 程序。

2.2.1 环境初始化 (master、node)

# 1.检查操作系统的版本
# 此方式下安装 kubernetes 集群要求 Centos 的版本在 7.5 或之上。
cat /etc/redhat-release

# 2.主机名解析
# 为了方便后面集群节点间的直接调用,在这配置一下主机名解析,企业中推荐使用内部的 DNS 服务器
# 主机名称解析 编辑三台服务器的 /etc/hosts 文件,添加下面内容
192.168.3.53 master
192.168.3.54 node1
192.168.3.55 node2

# 3.时间同步
# kubernetes 要求集群中的节点时间必须精确一致,这里直接使用 chronyd 服务从网络同步时间。企业中建议配置内部的时间同步服务器。
# 启动 chronyd 服务
systemctl start chronyd
# 设置 chronyd 服务开机自启动
systemctl enable chronyd
# chronyd 服务启动稍等几秒钟,就可以使用 date 命令验证时间了
date

# 4. 禁用 iptables 和 firewalld 服务。
# kubernetes 和 docker 在运行中会产生大量的 iptables 规则,为了不让系统规则跟它们混淆,直接关闭系统规则。
# 关闭 firewalld 服务
systemctl stop firewalld
systemctl disable firewalld
# 关闭 iptables 服务
systemctl stop iptables
systemctl disable iptables

# 5. 禁用 selinux 
# selinux 是 Linux 系统下的一个安全服务,如果不关闭它,在安装集群中会产生各种各样的奇葩问题。
# 编辑 /etc/selinux/config 文件,修改 SELINUX 的值为 disabled,注意修改完毕之后需要重启 linux 服务。
SELINUX=disabled

# 6. 禁用 swap 分区
# swap 分区指的是虚拟内存分区,它的作用是在物理内存用完之后,将磁盘空间虚拟成内存来使用,启用 swap 设备会对系统的性能产生非常负面的影响,因此 kubernetes 要求每个节点都要禁用 swap 设备,但是如果因为某些原因确实不能关闭 swap 分区,就需要在集群安装过程中通过明确的参数进行配置说明
# 编辑分区配置文件 /etc/fstab 注释掉 swap 分区一行,注意修改完毕之后,需要重启 linux 服务。
# /dev/mapper/centos-swap swap defaults 0 0

# 7. 修改 linux 内核参数
# 修改 linux 的内核参数,添加网桥过滤和地址转发功能。
# 编辑 /etc/sysctl.d/kubernetes.conf 文件,添加如下配置
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
# 重新加载配置
sysctl -p
# 加载网桥过滤模块
modprobe br_netfilter
# 查看网桥过滤模块是否加载成功
lsmod | grep br_netfilter

# 8. 配置 ipvs 功能
# 在 kubernetes 中 service 有两种代理模型,一种是基于 iptables 的,一种是基于 ipvs 的,两者比较的话,ipvs 的性能明显要高一些,但是如果要使用它,需要手动载入 ipvs 模块。
# 8.1 安装 ipset 和 ipvsadm
yum install ipset ipvsadmin -y
# 8.2 添加需要加载的模块写入脚本文件
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
# 8.3 为脚本文件添加执行权限
chmod +x /etc/sysconfig/modules/ipvs.modules
# 8.4 执行脚本文件
/bin/bash /etc/sysconfig/modules/ipvs.modules
# 8.5 查看对应的模块是否加载成功
lsmod | grep -e ip_vs -e nf_conntrack_ipv4

# 9. 重启服务器
# 上面步骤完成之后,需要重新启动 linux 系统。

2.2.2 docker 安装 (master、node)

# 1. 切换镜像源
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

# 2. 查看当前镜像源中支持的 docker 版本
yum list docker-ce --showduplicates

# 3. 安装特定版本的 docker-ce
# 必须指定 --setopt=obsoletes=0,否则yum会自动安装更高版本。
yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y

# 4. 添加一个配置文件
# Docker 在默认情况下使用 Cgroup Driver 为 cgroupfs,而 kubernetes 推荐使用 systemd 来代替 cgroupfs
mkdir /etc/docker
cat << EOF > /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "registry-mirrors": ["http://fl791z1h.mirror.aliyuncs.com"]
}
EOF

# 5. 启动 docker
systemctl restart docker
systemctl enable docker

# 6. 检查 docker 的状态和版本
docker version

2.2.3 kubernetes 组件安装 (master、node)

# 1. 添加国内镜像源
# 由于 kubernetes 的镜像源在国外,速度比较慢,这里切换成国内的镜像源
# 编辑 /etc/yum.repos.d/kubernetes.repo,添加下面的配置
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

# 2. 安装 kubeadm、kubelet、kubectl
yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y

# 3. 配置 kubelet 的 cgroup
# 编辑 /etc/sysconfig/kubelet,添加下面的配置
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"

# 4. 设置 kubelet 开机自启
systemctl enable kubelet 

2.2.4 准备集群镜像 (master、node)

# 1. 查看所需镜像
# 在安装 kubernetes 集群之前,必须要提前准备好集群需要的镜像。
kubeadm config images list

# 2. 下载镜像(可以省略)
# 此镜像在 kubernetes 的仓库中,由于网络原因,无法连接,下面提供了一种替代方案。适用上一步查出来的版本
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.5 集群初始化

下面开始对集群进行初始化,并将 node 节点加入到集群中。

下面的操作只需要在 master 节点上执行即可。

# 1. 创建集群 
# 镜像拉取加速 --image-repository=registry.aliyuncs.com/google_containers
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=192.168.3.53

# 2. 创建必要文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

下面的操作只需要在 node 节点上执行即可。

# 1. 将 node 节点加入集群, 注意 token 和 discovery-token-ca-cert-hash 的值请查看 master 初始化成功后的输出信息。
kubeadm join 192.168.3.53:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx
# 在 master 主机上查看集群状态
# 查看集群状态,此时的集群状态为 NotReady,这是因为还没有配置网络插件,
kubectl get nodes

2.2.6 安装网络插件

kubernetes 支持多种网络插件,比如 flannel、calico、canal 等等,任选一种使用即可,本次选择 flannel

下面的操作只需要在 master 节点执行即可,插件使用的是 DaemonSet 的控制器,它会在每个节点上都运行。

# 1. 获取 flannel 的配置文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 1.1 修改文件中 quary.io 仓库为 quary-mirror.qiniu.com

# 2. 使用配置文件启动 flannel
kubectl apply -f kube-flannel.yml

# 3. 稍等片刻,再次查看集群节点的状态
kubectl get nodes

2.3 服务部署 (master)

接下来在 kunernetes 集群中部署一个 nginx 程序,测试下集群是否在正常工作。

# 1. 部署 nginx
kubectl create deployment nginx --image=nginx:1.14-alpine

# 2. 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort

# 3. 查看服务状态
kubectl get pods,svc

# 4. 最后浏览器访问下部署的 nginx 服务,注意 port 请查看上一步输出的端口。
http://192.168.3.53:port

3. 资源管理

3.1 资源管理介绍

在 kubernetes 中,所有的内容都抽象为资源,用户需要操作资源来管理 kubernetes。

kubernetes 的本质上就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务,其实就是在 kubernetes 集群中运行一个个的容器,并将指定的程序跑在容器中。
kubernetes 的最小管理单元是 pod 而不是容器,所以只能将容器放在 Pod 中,而 kubernetes 一般也不会直接管理 Pod,而是通过 Pod 控制器来管理 Pod 的。
Pod 可以提供服务之后,就要考虑如何访问 Pod 中的服务,kubernetes 提供了 Service 资源实现这个功能。
当然,如果 Pod 中程序的数据需要持久化,kubernetes 还提供了各种存储系统。

kubernetes资源

学习 kubernetes 的核心,就是学习如何对集群上的 Pod、Pod控制器、Service、存储等各种资源进行操作。

3.2 YMAL 语法介绍

YAML 是一个类似 XML、JSON 的标记性语言。它强调以数据为中心,并不是以标识语言为重点。因而 YAML 本身的定义比较简单,号称 “一种人性化的数据格式语言”。

YAML 的语法比较简单,主要有下面几个:

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用 tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释

YAML 支持以下几种数据类型:

  • 纯量:单个的、不可再分的值
  • 对象:键值对的集合,又称映射(mapping)、哈希(hash)、字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence)、列表(list)
  1. 书写 yaml 切记 : 后面要加一个空格
  2. 如果需要将多段 yaml 配置放在一个文件中,中间要使用 分割
  3. yaml 转 json 的网站,可以通过它验证 yaml 是否书写正确

3.3 资源管理的方式

命令式对象管理:直接使用命令去操作 kubernetes 资源。

kubectl run nginx-pod --image=nginx:1.17.1 --port=80

命令式对象配置:通过命令配置和配置文件去操作 kubernetes 资源。

kubectl create/patch -f nginx-pod.yaml

声明式对象配置:通过 apply 命令和配置文件去操作 kubernetes 资源。

# apply 创建和更新
kubectl apply -f nginx-pod.yaml
类型操作对象适用环境优点缺点
命令式对象管理对象测试简单只能操作活动对象,无法审计、跟踪
命令式对象配置文件开发可以审计、跟踪项目大时,配置文件多,操作麻烦
声明式对象配置目录开发支持目录操作意外情况下难以调试

3.3.1 命令式对象管理

kubectl:是 kubernetes 集群的命令行工具,通过它能够对集群本身进行管理,并能够再集群上进行容器化应用的安装部署。

kubectl 命令的语法如下:

kubectl [command] [type] [name] [flags]
# 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 中所有的内容都抽象为资源,可以通过下面的命令查看:

kubectl api-resources

下面以一个 namespace 的创建和删除简单演示下命令的使用:

# 创建一个 namespace
kubectl create namespace dev
# 获取 namespace
kubectl get ns
# 在此 namespace 下创建并运行一个 nginx 的 pod
kubectl run pod --image=nginx -n dev
# 查看新创建的 pod
kubectl get pods -n dev
# 删除指定的 pod
kubectl delete pods pod-864f9875b9-4fvbd
# 删除指定的 namespace
kubectl delete ns dev

3.3.2 命令式对象配置

命令式对象配置就是使用命令配合配置文件一起来操作 kubernetes 资源。

创建一个 nginxpod.yaml,内容如下:

apiVersion: v1
kind: Namespace
metadata: 
  name: dev

---

apiVersion: v1
kind: Pod
metadata: 
  name: nginxpod
  namespace: dev
spec:
  containers:
    - name: nginx-containers
      image: nginx:1.17.1

执行命令,创建、查看、删除资源

# 1. 执行 create 命令,创建资源
kubectl create -f nginxpod.yaml
# 2. 执行 get 命令,查看资源
kubectl get -f nginxpod.yaml
# 3. 执行 delete 命令,删除资源
kubectl delete -f nginxpod.yaml

3.3.3 声明式对象配置

# 1. 执行 apply 命令,用于创建或更新资源,create、patch
kubectl apply -f nginxpod.yaml

4. 实战入门

如何在 kubernetes 集群中部署一个 nginx 服务,并且能够对齐进行访问。

4.1 Namespace

Namespace 是 kubernetes 系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。

Kubernetes 在集群启动之后,会默认创建几个 namespace:

  • default:所有未指定 Namespace 的对象都会被分配在 default 命名空间
  • kube-node-lease:集群节点之间的心跳维护,v1.13 开始引入
  • kube-public:此命名空间下的资源可以被所有人访问(包括未认证用户)
  • kube-system:所有由 Kubernetes 系统创建的资源都处于这个命名空间

下面是 namespace 资源的具体操作:

方式一命令

# 1. 查看所有的 namespace
kubectl get ns
# 2. 查看指定的 namespace
kubectl get ns default
# 3. 指定输出格式
# kubernetes 支持的格式很多,比如常见的是 wide、json、yaml
kubectl get ns default -o yaml
# 4. 查看 namespace 详情
kubectl describe ns default
# 5. 创建 namespace
kubectl create ns dev
# 6. 删除 namespace
kubectl delete ns dev

方式二配置:创建一个 ns-dev.yaml

apiVersion: v1
kind: Namespace
metadata: 
  name: dev
# 创建
kubectl create -f ns-dev.yaml
# 删除
kubectl delete -f ns-dev.yaml

4.2 Pod

Pod 是 kubernetes 集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于 Pod 中。

Pod 可以认为是容器的封装,一个 Pod 中可以存在一个或多个容器。

Kubernetes 在集群启动之后,集群中的各个组件也都是以 Pod 方式运行的。可以通过下面的命令查看

kubectl get pod -n kube-system

下面是 Pod 资源的具体操作:

方式一 命令

# 1. 创建并运行
kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
# 2. 查看 Pod 基本信息
kubectl get pods -n dev
# 3. 查看 Pod 额外信息
kubectl get pods -n dev -o wide
# 4. 查看 Pod 的详细信息
kubectl describe pod nginx-6867cdf567-77w9r -n dev
# 5. 查看 dev 命名空间的 Pod 控制器
kubectl get deployment -n dev
# 5. 删除, 先删除 deployment,pod 会自动删除
kubectl delete deployment nginx -n dev

方式二 配置: 创建一个 pod-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  container:
    - image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      name: pod
      ports: 
        - name: nginx-port
          containerPort: 80
          protocol: TCP
# 创建
kubectl create -f pod-nginx.yaml
# 删除
kubectl delete -f pod-nginx.yaml

4.3 Label

Label 是 kubernetes 系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label 的特点:

  • 一个 Label 会以 key/value 键值对的形式附加到各种对象上,如 Node、Pod、Service 等等。
  • 一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源对象上去。
  • Label 通常在资源对象定义的时确定,当然也可以在对象创建后动态添加或者删除。

可以通过 Label 实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。

一些常用 Label 示例如下:

# 版本标签
version: release
# 环境标签
environment: dev
# 架构标签
tier: frontend

标签定义完毕之后,还要考虑到标签的选择,这就要使用到 Label Selector,即:

  • Label 用于给某个资源对象定义标识
  • Label Selector 用于查询和筛选拥有某些标签的资源对象

当前有两种 Label Selector:

  • 基于等式的 Label Selector:name=slave 选择所有包含 Label 中 key=“name” 且 value=“slave” 的对象;env!=production 选择所有包括 Label 中的 key=“env” 且 value 不等于 “production” 的对象。
  • 基于集合的 Label Selector:name in (master,slave) 选择所有包含 Label 中的 key=“name” 且 value=“master” 或 “slave” 的对象;name not in (frontend) 选择所有包含 Label 中的 key=“name” 且 value 不等于 “frontend” 的对象。

标签的选择条件可以使用多个,此时将多个 Label Selector 进行组合,使用逗号 “,” 进行分割即可。例如

name=slave,env!=production
name not in (frontend),env!=production

下面是 Label 资源的具体操作:

方式一 命令

# 1. 为 Pod 资源打标签
kubectl label pod nginx-pod version=1.0 -n dev
# 2. 为 Pod 资源更新标签
kubectl label pod nginx-pod version=2.0 -n dev --overwrite
# 3. 查看标签
kubectl get pod nginx-pod -n dev --show-labels
# 4. 筛选标签
kubectl get pod -n dev -l version=2.0 --show-labels
kubectl get pod -n dev -l version!=2.0 --show-labels
# 5. 删除标签
kubectl label pod nginx-pod version- -n dev

方式二 配置: 创建一个 pod-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels: 
    version: "3.0"
    env: "test"
spec:
  container:
    - image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      name: pod
      ports: 
        - name: nginx-port
          containerPort: 80
          protocol: TCP
kubectl apply -f pod-nginx.yaml

4.4 Deployment

在 kubernetes 中,Pod 是最小的控制单元,但是 kubernetes 很少直接控制 Pod,一般都是通过 Pod 控制器来完成的。Pod 控制器用于 Pod 的管理,确保 pod 资源符合预期状态,当 Pod 的资源出现故障时,会尝试进行重启或重建 Pod。

在 kubernetes 中 Pod 控制器的种类有很多,本章节只介绍一种: Deployment。

下面是 Deployment 资源的具体操作:

方式一 命令

# 命令格式
kubectl run deployment名称 [参数]
# --image 指定 pod 的镜像
# --port 指定端口
# --replicas 指定创建 pod 的数量
# --namespace 指定namespace
# 1. 创建
kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
# 2. 查看创建的 pod
kubectl get pods -n dev
# 3. 查看 deployment 的信息
kubectl get deploy -n dev
# 4. 查看 deployment 的信息
kubectl get deploy -n dev -o wide
# 5. 查看 deployment 的详细信息
kubectl describe deploy nginx -n dev
# 6. 删除
kubectl delete deploy nginx -n dev

方式二 配置: 创建一个 deploy-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels: 
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
        - image: nginx:1.17.1
          name: pod
          ports: 
            - containerPort: 80
              protocol: TCP
# 创建
kubectl create -f deploy-nginx.yaml
# 删除
kubectl delete -f deploy-nginx.yaml

4.5 Service

利用 Deployment 可以创建一组 Pod 来提供具有高可用性的服务。

虽然每个 Pod 都会分配一个单独的 Pod IP,然而却存在如下两个问题:

  • Pod IP 会随着 Pod 的重建产生变化
  • Pod IP 仅仅是集群内可见的虚拟 IP,外部无法访问。

这样对于访问这个服务带来了难度。因此,kubernetes 设计了 Service 来解决这个问题。

Service 可以看作是一组同类 Pod 对外的访问接口。借助 Service,应用可以方便地实现服务发现和负载均衡。

方式一 命令

# 1. 暴露 Service 创建集群内部可访问的 Service
kubectl expose deploy nginx --name=svc-nginx --type=ClusterIP --port=80 --target-port=80 -n dev
# 2. 暴露 Service 创建集群外部可访问的 Service
kubectl expose deploy nginx --name=svc-nginx --type=NodePort --port=80 --target-port=80 -n dev
# 3. 查看 Service
kubectl get svc svc-nginx -n dev -o wide
# 4. 删除 Service
kubectl delete svc svc-nginx -n dev

方式二 配置:创建一个 svc-nginx.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 10.109.179.231
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
    selector:
      run: nginx
    type: ClusterIP
# 创建
kubectl create -f svc-nginx.yaml
# 删除
kubectl delete -f svc-nginx.yaml

5. Pod 详解

# Pod 基本配置
apiVersion: v1
kind: Pod
metadata:
  name: pod-test
  namespace: dev
spec:
  containers: 
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      resources: 
        limits: 
          cpu: "2"
          memory: "10Gi"
        requests:
          cpu: "1"
          memory: "10Mi"
    - name: busybox
      image: busybox:1.30
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh", "-c", "touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
      env: 
        - name: "username"
          value: "admin"
        - name: "password"
          value: "123456"

---

# 初始化容器 initContainers
apiVersion: v1
kind: Pod
metadata: 
  name: pod-init
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
  initContainers: 
    - name: test-mysql
      image: busybox:1.30
      commond: ["sh", "-c", "until ping 192.168.3.54 -c 1; do echo waiting for mysql ...; sleep 2; done;"]
    - name: test-redis
      image: busybox:1.30
      commond: ["sh", "-c", "until ping 192.168.3.55 -c 1; do echo waiting for redis ...; sleep 2; done;"]

---

# 钩子函数 postStart preStop
apiVersion: v1
kind: Pod
metadata: 
  name: pod-hook-exec
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
  lifecycle: 
    postStart:
      exec: 
        commond: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
    preStop:
      exec:
        commond: ["/usr/sbin/nginx", "-a", "quit"]

---

# 容器探测 方式一 exec
apiVersion: v1
kind: Pod
metadata: 
  name: pod-liveness-exec
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
      livenessProbe: #readinessProbes
        exec:
          command: ["/bin/cat", "/tmp/hello.txt"]

---

# 容器探测 方式二 TCPSocket
apiVersion: v1
kind: Pod
metadata: 
  name: pod-liveness-exec
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
      livenessProbe: #readinessProbes
        tcpSocket:
          port: 8080

---

# 容器探测 方式二 HTTPGet
apiVersion: v1
kind: Pod
metadata: 
  name: pod-liveness-httpget
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
      livenessProbe: #readinessProbes
        httpGet:
          scheme: HTTP
          port: 8080
          path: /hello
        initialDelaySeconds: 30
        timeoutSeconds: 5

---

# 重启策略 restartPolicy
apiVersion: v1
kind: Pod
metadata: 
  name: pod-restartpolicy
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
      ports:
        - name: nginx-port
          containerPort: 80
      livenessProbe: #readinessProbes
        httpGet:
          scheme: HTTP
          port: 8080
          path: /hello
        initialDelaySeconds: 30
        timeoutSeconds: 5
  restartPolicy: Always

---

# Pod调度 定向调度 nodename
apiVersion: v1
kind: Pod
metadata: 
  name: pod-nodename
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  nodeName: node1

---

# Pod调度 定向调度 nodeSelector
apiVersion: v1
kind: Pod
metadata: 
  name: pod-nodeselector
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  nodeSelector: 
    nodeenv: pro

---

# Pod调度 亲和性调度 nodeaffinity required
apiVersion: v1
kind: Pod
metadata: 
  name: pod-nodeaffinity-required
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: 
        nodeSelectorTerms:
          - matchExprassions:
            - key: nodeenv
              operator: In
              values: ["xxx", "yyy"]

---

# Pod调度 亲和性调度 nodeaffinity preferred
apiVersion: v1
kind: Pod
metadata: 
  name: pod-nodeaffinity-preferred
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution: 
        - weight: 1
        preference:
          - matchExpressions:
            - key: nodeenv
              operator: In
              values: ["xxx", "yyy"]

---

# Pod调度 亲和性调度 pod affinity required
apiVersion: v1
kind: Pod
metadata: 
  name: pod-podaffinity-required
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: 
        - labelSelector:
          matchExpressions:
            - key: podenv
              operator: In
              values: ["xxx", "yyy"]
        topologKey: kubernetes.io/hostname

---

# Pod调度 亲和性调度 pod antiaffiaity
apiVersion: v1
kind: Pod
metadata: 
  name: pod-podantiaffiaity-required
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: 
        - labelSelector:
          matchExpressions:
            - key: podenv
              operator: In
              values: ["xxx", "yyy"]
        topologKey: kubernetes.io/hostname

---

# Pod调度 污点和容忍
# 污点 PreferNoSchedule、NoSchedule、NoExecute
# Pod调度 容忍
apiVersion: v1
kind: Pod
metadata: 
  name: pod-toleration
  namespace: dev
spec: 
  containers:
    - name: main-container
      image: nginx:1.17.1
  tolerations:
    - key: "key" # 污点的key
      operator: "Equal"
      value: "value" # 污点的value
      effect: "NoExecute"

# 创建 Pod
kubectl create -f pod-test.yaml
# 进入指定的容器
kubectl exec pod-test -n dev -it -c busybox /bin/sh
# 为 node 节点添加标签
kubectl label nodes node1 nodeenv=pro
# 为 node 设置污点 effect: PreferNoSchedule、NoSchedule、NoExecute
kubectl taint nodes node1 key=value:effect
# 去除 污点 
kubectl taint nodes node1 key:effect-
# 去除所有污点
kubectl taint nodes node1 key-
# 删除
kubectl delete -f pod-test.yaml

6. Pod 控制器详解

# Pod控制器 ReplicaSet
apiVersion: apps/v1
kind: ReplicaSet
metadata: 
  name: pc-replicaset
  namespace: dev
  labels:
    controller: rs
spec: 
  replicas: 3
  selector: 
    matchLabels:
      app: nginx-pod
    matchExpressions:
      - {key: app, operator: In, values: [nginx-pod]}
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80

---

# Pod控制器 Deployment
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: pc-deployment
  namespace: dev
  labels:
    controller: deploy
spec: 
  replicas: 3
  revisionHistoryLimit: 10
  paused: false
  progressDeadlineSeconds: 600
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 30%
      maxUnavailable: 30%
  selector: 
    matchLabels:
      app: nginx-pod
    matchExpressions:
      - {key: app, operator: In, values: [nginx-pod]}
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80

---

# Pod控制器 Horizontal Pod Autoscaler
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata: 
  name: pc-hpa
  namespace: dev
spec: 
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 3
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx

---

# Pod控制器 DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata: 
  name: pc-ds
  namespace: dev
spec: 
  selector: 
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
---

# Pod控制器 Job
apiVersion: batch/v1
kind: Job
metadata: 
  name: pc-job
  namespace: dev
spec: 
  manualSelector: true
  completions: 1
  parallelism: 1
  selector: 
    matchLabels:
      app: counter-pod
  template:
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never
      containers:
        - name: counter
          image: busybox:1.30
          command: ["/bin/sh", "-c", "for i in 9 8 7 6 5 4 3 2 1; do echo $i; sleep 3; done;"]

---

# Pod控制器 Cronjob
apiVersion: batch/v1beta1
kind: CronJob
metadata: 
  name: pc-cronjob
  namespace: dev
  labels:
    controller: cronjob
spec: 
  schedule: "*/1 * * * *"
  jobTemplate:
    metadata:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: counter
              image: busybox:1.30
              command: ["/bin/sh", "-c", "for i in 9 8 7 6 5 4 3 2 1; do echo $i; sleep 3; done;"]
# 编辑 pc-replicaset yaml 实现扩缩容
kubectl edit rs pc-replicaset -n dev
# 命令 实现扩缩容
kubectl scale rs pc-replicaset --replicas=2 -n dev
# 镜像升级
kubectl set image rs pc-replicaset nginx=nginx:1.17.2 -n dev
# 删除 Pod 和 Pod 控制器
kubectl delete rs pc-replicaset -n dev
# 删除 Pod 和 Pod 控制器
kubectl delete -f pc-replicaset.yaml
# 删除 Pod 控制器
kubectl delete rs pc-replicaset -n dev --cascade=false

# 编辑 pc-deployment yaml 实现扩缩容
kubectl edit deploy pc-deployment -n dev
# 命令 实现扩缩容
kubectl scale deploy pc-deployment --replicas=2 -n dev
# 镜像更新策略 Recreate、RollingUpdate
# 镜像升级
kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev
# 创建 --record 会记录下更新的过程
kubectl create -f pc-deployment.yaml --record
# 查看当前升级版本的状态
kubectl rollout status deploy pc-deployment -n dev
# 查看升级历史记录
kubectl rollout history deploy pc-deployment -n dev
# 版本回滚 --to-revision=1 回滚到1版本,省略此项,回滚到上一个版本,2版本
kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
# 金丝雀发布
# 更新 deployment 的版本,并配置暂停 deployment
kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev && kubectl rollout pause deploy pc-deployment -n dev
# 确保更新的 Pod 没有问题。继续更新
kubectl rollout resume deploy pc-deployment -n dev

# Horizontal Pod Autoscaler 相关软件
# 安装 metrics-server 用于收集集群中的资源的使用情况。
# 安装 git
yum install git -y
# 获取 metrics-server 
git clone -b release-0.3 https://github.com/kubernetes-sigs/metrics-server.git
# 修改 deployment,镜像和初始化参数
cd ./metrics-server/deploy/1.8+/
vim metrics-server-deployment.yaml
# 添加以下内容 详细配置请看下面 metrics-server-deployment.yaml
#hostNetwork: true
#registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
#- --kubelet-insecure-tls
#- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
# 安装 ab 用于压测
yum -y install httpd-tools
#-n 访问的总次数,-c 访问的并发量
ab -n 10000 -c 5000 http://192.168.3.53:31606/
# metrics-server-deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metrics-server
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-server
  namespace: kube-system
  labels:
    k8s-app: metrics-server
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  template:
    metadata:
      name: metrics-server
      labels:
        k8s-app: metrics-server
    spec:
      serviceAccountName: metrics-server
      hostNetwork: true
      volumes:
      # mount in tmp so we can safely use from-scratch images and/or read-only containers
      - name: tmp-dir
        emptyDir: {}
      containers:
      - name: metrics-server
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
        imagePullPolicy: IfNotPresent
        args:
          - --cert-dir=/tmp
          - --secure-port=4443
          - --kubelet-insecure-tls
          - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
        ports:
        - name: main-port
          containerPort: 4443
          protocol: TCP
        securityContext:
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
        volumeMounts:
        - name: tmp-dir
          mountPath: /tmp
      nodeSelector:
        kubernetes.io/os: linux

7. Service

# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels: 
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: pod
          image: nginx:1.17.1
          ports: 
            - containerPort: 80
              protocol: TCP

---

# ClusterIP 类型的 Service
apiVersion: v1
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  sessionAffinity: ClientIP # 可选值 ClientIP、None
  selector:
    app: nginx-pod
  clusterIP: 10.96.41.139
  type: ClusterIP
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80

---

# HeadLiness 类型的 Service
apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 80

--- 

# NodePort 类型的 Service
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort
  ports:
    - port: 80
      nodePort: 30002 # 如果不指定,默认的取值范围 30000 - 32767
      targetPort: 80

---

# LoadBalancer 类型的 Service
# 需要外设,用到了补充
---

# ExternalName 类型的 Service
apiVersion: v1
kind: Service
metadata:
  name: service-externalname
  namespace: dev
spec:
  type: ExternalName
  externalName: www.baidu.com

# 管理Linux虚拟服务器
yum -y install ipvsadm
ipvsadm -Ln
# 开启 ipvs,修改 mode 设置值为 ipvs
kubectl edit cm kube-proxy -n kube-system
# 根据 k8s-app=kube-proxy 标签删除 Pod
kubectl delete pod -l k8s-app=kube-proxy -n kube-system
# 进入 Pod,echo "node1 nginx ..." > /usr/share/nginx/html/index.html
kubectl exec -it pc-deployment-9ff4869f5-9xs2s -n dev /bin/bash
# 查询 endpoints 
kubectl get endpoints -n dev
# 进入 Pod 查看域名解析情况,用于访问 HeadLiness Service
cat /etc/resolv.conf
# 安装 dig 命令
yum -y install bind-utils
# 查询域名解析
dig @10.96.0.10 service-headliness.dev.svc.cluster.local

7.1 Ingress

7.1.1 Ingress 介绍

7.1.2 Ingress 使用

安装 Ingress:

# 创建文件夹
mkdir ingress-controller
cd ingress-controller
# 获取 ingress-nginx
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
# 修改 mandatory.yaml 文件中的仓库
# 修改 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 为 quay-mirror.qiniu.com/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 创建 ingress-nginx
kubectl apply -f ./
# 查看 ingress-nginx
kubectl get pod -n ingress-nginx
# 查看 service
kubectl get svc -n ingress-nginx

准备 Service、Pod:新增 nginx-tomcat.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels: 
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - image: nginx:1.17.1
          name: nginx
          ports: 
            - containerPort: 80
              protocol: TCP

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels: 
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
        - image: tomcat:8.0
          name: tomcat
          ports: 
            - containerPort: 8080
              protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
# 删除命名空间 排除影响
kubectl delete ns dev
# 创建 dev 命名空间
kubectl create ns dev
# 创建 测试的 service、pod
kubectl create -f nginx-tomcat.yaml
# 查看是否创建成功
kubectl get svc,deploy,pod -n dev

http 代理:新增 ingress-http.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules: 
    - host: nginx.joe.com
      http:
        paths: 
          - path: /
            backend: 
              serviceName: nginx-service
              servicePort: 80
    - host: tomcat.joe.com
      http:
        paths: 
          - path: /
            backend: 
              serviceName: tomcat-service
              servicePort: 8080
# 创建 Ingress
kubectl create -f ingress-http.yaml
# 查看是否创建成功
kubectl get ingress -n dev
kubectl describe ing ingress-http -n dev
# 需要在测试主机添加 dns 解析
# /etc/hosts 
# 192.168.3.53 nginx.joe.com
# 192.168.3.53 tomcat.joe.com
# 查看代理的端口
kubectl get svc -n ingress-nginx
# 测试访问 
# http://nginx.joe.com:31913/
# http://tomcat.joe.com:31913/

https 代理:新增 ingress-https.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls:
    - hosts: 
      - nginx.joe.com
      - tomcat.joe.com
      secretName: tls-secret # 指定密钥
  rules: 
    - host: nginx.joe.com
      http:
        paths: 
          - path: /
            backend: 
              serviceName: nginx-service
              servicePort: 80
    - host: tomcat.joe.com
      http:
        paths: 
          - path: /
            backend: 
              serviceName: tomcat-service
              servicePort: 8080
# 创建证书
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=joe.com"
# 创建密钥
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
# 创建 ingress-https
kubectl create -f ingress-https.yaml
# 查看是否创建成功
kubectl get ingress -n dev
kubectl describe ing ingress-https -n dev
# 需要在测试主机添加 dns 解析
# /etc/hosts 
# 192.168.3.53 nginx.joe.com
# 192.168.3.53 tomcat.joe.com
# 查看代理的端口
kubectl get svc -n ingress-nginx
# 测试访问 
# https://nginx.joe.com:30601/
# https://tomcat.joe.com:30601/

8. 数据存储

为了持久化保存容器的数据,kubernetes 引入了 Volume 的概念。

volume 是 Pod 中能够被多个容器访问的共享目录,它被定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下,kubernetes 通过 volume 实现同一个 Pod 中不同容器之间的数据共享以及数据的持久化存储。

volume 的生命周期不与 Pod 中单个容器的生命周期相关,当容器终止或重启时,volume 中的数据也不会丢失。

kubernetes 的 volume 支持多种类型,比较常见的有下面几个:

  • 简单存储:EmptyDir、HostPath、NFS
  • 高级存储:PV、PVC
  • 配置存储:ConfigMap、Secret

8.1 基本存储

8.1.1 EmptyDir

EmptyDir 是最基础的 Volume 类型,一个 EmptyDir 就是 Host 上的一个空目录。

EmptyDir 是在 Pod 被分配到 Node 时创建的,它的初始内容为空,并且无需指定宿主机上对应的目录文件,因为 kubernetes 会自动分配一个目录,当 Pod 销毁时,EmptyDir 中的数据也会被永久删除。

EmptyDir 的用途:

  • 临时空间:例如用于某些应用程序运行时所需的临时目录,且无需永久保留。
  • 一个容器需要从另一个容器中获取数据的目录。(多容器共享目录)

通过一个容器之间文件共享的案例来使用 EmptyDir :在一个 Pod 中准备两个容器 nginx 和 busybox, 然后声明一个 volume 分别挂载到两个容器的目录中,然后 nginx 容器负责向 volume 中写日志,容器 busybox 中通过命令将日志读到控制台。

volumeEmptyDirExample

创建 volume-emptydir.yaml

apiVersion: v1
kind: Pod
metadata: 
  name: volume-emptydir
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      ports: 
        - containerPort: 80
      volumeMounts: 
        - name: logs-volume
          mountPath: /var/log/nginx
    - name: busybox
      image: busybox:1.30
      command: ["/bin/sh", "-c", "tail -f /logs/access.log"]
      volumeMounts: 
        - name: logs-volume
          mountPath: /logs
  volumes:
    - name: logs-volume
      emptyDir: {}
# 创建 pod
kubectl create -f volume-emptydir.yaml
# 查看 Pod
kubectl get pods volume-emptydir -n dev -o wide
# 根据 podip 访问 nginx 
curl podip:80
# 查看指定容器的标准输出
kubectl logs -f volume-emptydir -n dev -c busybox

8.1.2 HostPath

如果想简单的将数据持久化到主机中,可以选择 HostPath。

HostPath 就是将 node 主机中一个实际目录挂载到 Pod 中,以供容器使用,这样的设计就可以保证 Pod 销毁了,但是数据依旧可以存在于 Node 主机上。

volumeHostPathExample

创建一个 volume-hostpath.yaml

apiVersion: v1
kind: Pod
metadata: 
  name: volume-hostpath
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      ports: 
        - containerPort: 80
      volumeMounts: 
        - name: logs-volume
          mountPath: /var/log/nginx
    - name: busybox
      image: busybox:1.30
      command: ["/bin/sh", "-c", "tail -f /logs/access.log"]
      volumeMounts: 
        - name: logs-volume
          mountPath: /logs
  volumes:
    - name: logs-volume
      hostPath: 
        path: /root/logs
        type: DirectoryOrCreate # 目录存在就使用,不存在就创建。可选值:DirectoryOrCreate、Directory、FileOrCreate、File、Socket、CharDevice、BlockDevice

8.1.3 NFS

HostPath 可以解决数据的持久化的问题,但是一旦 Node 节点故障了,Pod 如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比如常用的 NFS、CIFS

NFS 是一个网络文件存储系统,可以搭建一台 NFS 服务器,然后将 Pod 中的存储直接连接到 NFS 系统上,这样的话,无论 Pod 在节点上怎么转移,只要 Node 跟 NFS 的对接没有问题,数据就可以成功访问。

首先要准备 NFS 服务器。

# 源服务器和目标服务器都需要安装 nfs-utils
yum install nfs-utils rpcbind -y
# 准备一个共享目录
mkdir ~/Data/nfs -pv
# 目标主机加权限,将共享目录以读写权限暴露给 192.168.3.0/24 网段中的所有主机。
tee /etc/exports <<-'EOF'
/root/Data/nfs        192.168.3.0/24(rw,sync,no_root_squash)
EOF
# 刷新
exportfs -ar
# 启动 NFS 服务
systemctl start nfs
systemctl start rpcbind
# 设置开机自启
systemctl enable nfs
systemctl enable rpcbind

创建一个 volume-nfs.yaml

apiVersion: v1
kind: Pod
metadata: 
  name: volume-nfs
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      ports: 
        - containerPort: 80
      volumeMounts: 
        - name: logs-volume
          mountPath: /var/log/nginx
    - name: busybox
      image: busybox:1.30
      command: ["/bin/sh", "-c", "tail -f /logs/access.log"]
      volumeMounts: 
        - name: logs-volume
          mountPath: /logs
  volumes:
    - name: logs-volume
      nfs: 
        server: 192.168.3.56
        path: /root/Data/nfs/nginxLogs

8.3 高级存储

8.3.1 PV 和 PVC

为了能够屏蔽底层存储实现的细节,方便用户使用,kubernetes 引入了 PV 和 PVC 两种资源对象。

  • PV (Persistent Volume) 持久卷,是对底层的共享存储的一种抽象。一般情况下 PV 由 kubernetes 管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
  • PVC (Persistent Volume Claim) 持久化卷声明,是用户对于存储需求的一种声明。换句话说,PVC 其实就是用户向 kubernetes 系统发出的一种资源需求申请。

pvAndpvc

使用了 PV 和 PVC 之后,工作可以得到进一步的细分:

  • 存储:存储工程师维护
  • PV:kubernetes 用户维护

8.3.2 PV

实验:使用 NFS 作为存储,创建 3 个 PV,对应 NFS 中的3个暴露的路径。

在 NFS 服务器中创建目录、修改配置、重启服务

# 创建目录
mkdir /root/Data/nfs/{pv1,pv2,pv3} -pv
# 暴露服务
tee /etc/exports <<-'EOF'
/root/Data/nfs        192.168.3.0/24(rw,sync,no_root_squash)
EOF
# 重启服务
systemctl restart nfs

创建 pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/Data/nfs/pv1
    server: 192.168.3.56

---

apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv2
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/Data/nfs/pv2
    server: 192.168.3.56

---

apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv3
spec:
  capacity:
    storage: 3Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/Data/nfs/pv3
    server: 192.168.3.56
# 创建 pv
kubectl create -f pv.yaml
# 查看
kubectl get pv -o wide

8.3.3 PVC

实验:创建 pvc、pod, 并 pod 使用 pv。

创建 pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: pvc1
  namespace: dev
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: pvc2
  namespace: dev
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: pvc3
  namespace: dev
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
# 创建 pvc
kubectl create -f pvc.yaml
# 查询
kubectl get pvc -n dev

创建 pods.yaml, 使用 pv

apiVersion: v1
kind: Pod
metadata: 
  name: pod1
  namespace: dev
spec:
  containers:
    - name: busybox
      image: busybox:1.30
      command: ["/bin/sh", "-c", "while true; do echo pod1 >> /root/out.txt; sleep 10; done;"]
      volumeMounts: 
        - name: volume
          mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim: 
        claimName: pvc1
        readOnly: false

---

apiVersion: v1
kind: Pod
metadata: 
  name: pod2
  namespace: dev
spec:
  containers:
    - name: busybox
      image: busybox:1.30
      command: ["/bin/sh", "-c", "while true; do echo pod2 >> /root/out.txt; sleep 10; done;"]
      volumeMounts: 
        - name: volume
          mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim: 
        claimName: pvc2
        readOnly: false
# 创建 pod
kubectl create -f pods.yaml
# 查询
kubectl get pods pod1 -n dev
kubectl get pods pod2 -n dev

8.3.4 生命周期

PVC 和 PV 是一一对应的,PV 和 PVC 之间的相互作用遵循以下生命周期。

pv和pvc的相互关系

8.4 配置存储

8.4.1 configMap

ConfigMap 是一种比较特殊的存储卷,它的作用是用来存储配置信息的。

创建 configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata: 
  name: configmap
  namespace: dev
data:
  info: 
    username:admin
    password:123456
# 创建
kubectl create -f configmap.yaml
# 查看
kubectl describe cm configmap -n dev

创建一个 pod-configmap.yaml, 将 configmap 挂载进去

apiVersion: v1
kind: Pod
metadata: 
  name: pod-configmap
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      ports: 
        - containerPort: 80
      volumeMounts: 
        - name: config
          mountPath: /configmap/config
  volumes:
    - name: config
      configMap: 
        name: configmap
# 创建 pod
kubectl create -f pod-configmap.yaml 
# 查看
kubectl get pods pod-configmap -n dev
# 进入容器
kubectl exec -it pod-configmap -n dev /bin/sh
# 查看容器内的文件
cd /configmap/config
more info

8.4.2 secret

Secret 它主要用于存储敏感信息,例如:密码、密钥、证书

首先使用 base64 对数据进行编码

# 准备 admin 的 base64 编码
echo -n 'admin' | base64
# 准备 123456 的 base64 编码
echo -n '123456' | base64

创建 secret.yaml

apiVersion: v1
kind: Secret
metadata: 
  name: secret
  namespace: dev
type: Opaque
data:
  username: YWRtaW4=
  password: MTIzNDU2
# 创建 secret
kubectl create -f secret.yaml
# 查看
kubectl describe secret/secret -n dev

创建一个 pod-secret.yaml 将 secret 挂载进去

apiVersion: v1
kind: Pod
metadata: 
  name: pod-secret
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      ports: 
        - containerPort: 80
      volumeMounts: 
        - name: config
          mountPath: /secret/config
  volumes:
    - name: config
      secret: 
        secretName: secret
# 创建 pod
kubectl create -f pod-secret.yaml 
# 查看
kubectl get pods pod-secret -n dev
# 进入容器
kubectl exec -it pod-secret -n dev /bin/sh
# 查看容器内的文件
cd /secret/config
more password
more username

9. 安全认证

9.1 访问控制概述

kubernetes 作为一个 分布式集群的管理工具,保证集群的安全性是其一个重要的任务。所谓安全性其实就是保证对 kubernetes 的各种客户端进行认证和鉴权操作。

在 kubernetes 集群中,客户端通常有两类:

  • User Account:一般是独立于 kubernetes 之外的其他服务管理的用户账号。
  • Service Account:kubernetes 管理的账号,用于为 Pod 中的服务进程在访问 kubernetes 时提供身份标识。

kubernetes客户端

认证、授权、准入机制:ApiServer 是访问及管理资源对象的唯一入口,任何一个请求访问 ApiServer, 都要经过下面的三个流程:

apiServer执行的流程

9.2 认证管理

kubernetes 集群安全的最关键点在于如何识别并认证客户端身份,它提供了3种客户端身份认证方式:

  • Http Base 认证:通过用户名+密码的方式认证
  • Http token 认证: 通过一个 token 来识别一个用户
  • Https证书认证:基于 CA 根证书签名的双向数字证书认证方式

Https 认证流程

https认证流程

9.3 授权管理

API Server 目前支持以下几种策略:

  • AlwaysDeny: 表示拒绝所有请求,一般用于测试
  • AlwaysAllow:允许接收所有请求,相当于集群不需要授权流程(kubernetes 默认策略)
  • ABAC: 基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
  • Webhook: 通过调用外部 Rest 服务对用户进行授权
  • Node: 是一种专用模式,用于对 kubelet 发出的请求进行访问控制。
  • RBAC:基于角色的访问控制(kubeadm 安装方式下的默认选项)

RBAC 引入了 4 个顶级资源对象:

  • Role、ClusterRole: 角色用于指定一组权限。
  • RoleBinding、ClusterRoleBinding: 角色绑定,用于将角色(权限)赋予给对象。

实验:创建一个只能管理 dev 空间下 pods 资源的账号

创建账号:

# 创建证书
cd /etc/kubernetes/pki/
(umask 007;openssl genrsa -out devman.key 2048)
# 用 Api Server 的证书去签署
# 签名申请,申请的用户是 devman, 组是 devgroup
openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"
# 签署证书
openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650
# 设置集群、用户、上下文信息
kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.3.53:6443
kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman
# 切换账户到 devman
kubectl config use-context devman@kubernetes
# 查看 pods 
kubectl get pods -n dev
# 切换到 admin 账户
kubectl config use-context kubernetes-admin@kubernetes

创建 Role 和 RoleBinding, 为 devman 用户授权: 创建 dev-role.yaml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: dev-role
  namespace: dev
rules: 
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]

---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
  - kind: User
    name: devman
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-role
  apiGroup: rbac.authorization.k8s.io
# 创建
kubectl create -f dev-role.yaml
# 切换账户到 devman
kubectl config use-context devman@kubernetes
# 查看 pods 
kubectl get pods -n dev

9.4 准入控制

通过认证和授权之后,还需要经过准入控制处理通过后,api server 才会处理这个请求。

准入控制是一个可配置的控制器列表,可以在 Api-Server 上通过命令行设置选择执行哪些准入控制器

--admission-control=NamespaceLifecycle,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds

10. DashBoard

kubernetes 开发了一个基于 web 的用户界面(DashBoard), 用户可以使用 DashBoard 部署容器化的应用,还可以监控应用的状态,执行故障排查以及管理 kubernetes 中各种资源。

10.1 部署 DashBoard

下载 yaml, 并运行 DashBoard

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml

修改 kubernetes-dashboard 的 service 类型

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Namespace
metadata:
  name: kubernetes-dashboard

---

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort # 新增
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30009 # 新增
  selector:
    k8s-app: kubernetes-dashboard

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-certs
  namespace: kubernetes-dashboard
type: Opaque

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-csrf
  namespace: kubernetes-dashboard
type: Opaque
data:
  csrf: ""

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-key-holder
  namespace: kubernetes-dashboard
type: Opaque

---

kind: ConfigMap
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-settings
  namespace: kubernetes-dashboard

---

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
rules:
  # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
    verbs: ["get", "update", "delete"]
    # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["kubernetes-dashboard-settings"]
    verbs: ["get", "update"]
    # Allow Dashboard to get metrics.
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["heapster", "dashboard-metrics-scraper"]
    verbs: ["proxy"]
  - apiGroups: [""]
    resources: ["services/proxy"]
    resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
    verbs: ["get"]

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
rules:
  # Allow Metrics Scraper to get metrics from the Metrics server
  - apiGroups: ["metrics.k8s.io"]
    resources: ["pods", "nodes"]
    verbs: ["get", "list", "watch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kubernetes-dashboard
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      containers:
        - name: kubernetes-dashboard
          image: kubernetesui/dashboard:v2.0.0
          imagePullPolicy: Always
          ports:
            - containerPort: 8443
              protocol: TCP
          args:
            - --auto-generate-certificates
            - --namespace=kubernetes-dashboard
            # Uncomment the following line to manually specify Kubernetes API server Host
            # If not specified, Dashboard will attempt to auto discover the API server and connect
            # to it. Uncomment only if the default does not work.
            # - --apiserver-host=http://my-address:port
          volumeMounts:
            - name: kubernetes-dashboard-certs
              mountPath: /certs
              # Create on-disk volume to store exec logs
            - mountPath: /tmp
              name: tmp-volume
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /
              port: 8443
            initialDelaySeconds: 30
            timeoutSeconds: 30
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      volumes:
        - name: kubernetes-dashboard-certs
          secret:
            secretName: kubernetes-dashboard-certs
        - name: tmp-volume
          emptyDir: {}
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 8000
      targetPort: 8000
  selector:
    k8s-app: dashboard-metrics-scraper

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: dashboard-metrics-scraper
  template:
    metadata:
      labels:
        k8s-app: dashboard-metrics-scraper
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
    spec:
      containers:
        - name: dashboard-metrics-scraper
          image: kubernetesui/metrics-scraper:v1.0.4
          ports:
            - containerPort: 8000
              protocol: TCP
          livenessProbe:
            httpGet:
              scheme: HTTP
              path: /
              port: 8000
            initialDelaySeconds: 30
            timeoutSeconds: 30
          volumeMounts:
          - mountPath: /tmp
            name: tmp-volume
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      volumes:
        - name: tmp-volume
          emptyDir: {}

# 部署
kubectl create -f recommended.yaml
# 查看
kubectl get pod,svc -n kubernetes-dashboard

创建访问账户、获取 token

# 创建账号
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
# 授权
kubectl create clusterrolebinding dashboard-admin-rb --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
# 获取账号 token
kubectl get secrets -n kubernetes-dashboard | grep dashboard-admin
# 使用 上一步查到的 dashboard-admin-token-xbqhh 查询详情
kubectl describe secrets dashboard-admin-token-xbqhh -n kubernetes-dashboard

火狐浏览器访问成功

在这里插入图片描述

11. 常用命令

# 查看 配置项
kubectl explain pod.metadata
# 查看资源
kubectl api-resources
# 监控 Pod
kubectl get pods -n dev -w
# 查看 node 资源的使用情况
kubectl top node
# 查看 pod 资源的使用情况
kubectl top pod -n kube-system
# 查看指定容器的标准输出
kubectl logs -f volume-emptydir -n dev -c busybox

12. docker 批量操作技巧

# 停止全部容器,并且删除全部容器
docker stop $(docker ps -q) & docker rm $(docker ps -aq)
# 删除全部镜像
docker rmi $(docker images -q)

参考文献

黑马程序员
kubernetes 官网
ab工具
Linux命令大全(手册)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/254428.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高可用接入层技术演化及集群概述

集群概述 集群的介绍及优势 集群&#xff1a;将多台服务器通过硬件或软件的方式组合起来&#xff0c;完成特定的任务&#xff0c;而这些服务器对外表现为一个整体。集群的优势 高可靠性&#xff1a;利用集群管理软件&#xff0c;当主服务器故障时&#xff0c;备份服务器能够自…

Cesium 加载 Geoserver WMS 图层以及条件查询和切换图层样式

Cesium 加载 Geoserver WMS 图层以及条件查询和切换图层样式 图层样式核心代码完整代码&#xff1a;在线示例 Cesium 加载 Geoserver WMS 图层&#xff0c;在实际项目中常常会遇到&#xff0c;需要对图层进行过滤&#xff0c;这里介绍一下过滤方法。 Cesium Geoserver 图层条件…

AirPodsPro3爆料汇总,2025年发布?

不止是iPhone&#xff0c;苹果的AirPods Pro系列耳机也是非常受用户青睐的一款产品&#xff0c;相信不少果粉都非常期待它的升级换代。 第一代AirPods Pro于2019年10月发布&#xff0c;第二代AirPods Pro于2022年9月发布&#xff0c;按照这个时间线来看的话&#xff0c;第三代A…

《Linux C编程实战》笔记:进程操作之创建进程

进程是一个动态的实体&#xff0c;是程序的一次执行过程。进程是操作系统资源分配的基本单位。 以下是一些概念&#xff0c;我就直接抄书了 进程是操作系统的知识&#xff0c;简单理解的话&#xff0c;你写的代码运行起来算一个进程&#xff1f; 创建进程 每个进程由进程ID号…

在vue项目中,数据已经在页面渲染,但在后续操作时获取不到数据

如下图 产生这个问题的原因 异步问题 如何解决 方法一&#xff1a;可以将其存放在一个setTimeout里面&#xff08;利用一个极小的延迟来获取数据&#xff09;&#xff0c;如下图 效果 方法二&#xff1a;将操作放入axios里面&#xff0c;如下图

昂首资本发现原油价差这样用,难怪银行这么富

难怪银行这么富&#xff0c;原来是发现一个稳定产生利益的投资策略。虽然这个利润可能看起来比较少。但是昂首资本需要提醒各位投资者的是&#xff1a;首先&#xff0c;这个策略几乎没有风险。第二&#xff0c;这是一个可以复制的投资策略。 下面昂首资本就通过原油的价差进行实…

开发信怎么写回复率高?写外贸邮件的技巧?

如何打造高回复率的开发信&#xff1f;有效的开发信模板推荐&#xff1f; 如何写一封能够引起客户兴趣并提高回复率的开发信变得至关重要。开发信是建立联系、促进销售和扩大业务的关键工具之一。蜂邮EDM将探讨一些关键策略&#xff0c;帮助你提高开发信的回复率&#xff0c;确…

爬虫图片验证码处理

图片验证码处理 目前&#xff0c;很多网站为了防止爬虫爬取&#xff0c;登录时需要用户输入验证码。下面我们学习如何在爬虫程序中识别验证码。 其中包含验证码。 页面中的验证码图片对应一个<img>元素&#xff0c;即一张图片&#xff0c;浏览器加载完登录页面后&#…

Spring 6(二)【IOC原理】

前言 IOC 是Spring的两大核心概念之一&#xff0c;它是一种思想&#xff0c;需要极其熟练的掌握。 今日摘录&#xff1a; 低能无聊的人太多。说他们勤勉&#xff0c;不过是因困为不会合理分配时间&#xff1b;说他们积极&#xff0c;不过是逃避其他困难工作而已。即便说工作只…

DNN二分类模型

import os import datetime#打印时间 def printbar():nowtime datetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S)print("\n"""*8 "%s"%nowtime)#mac系统上pytorch和matplotlib在jupyter中同时跑需要更改环境变量 os.environ["KMP_DUP…

【网络安全】-Linux操作系统—操作系统发展历史与Linux

文章目录 操作系统发展历史初期的操作系统分时操作系统个人计算机操作系统 Linux的诞生UNIX与GNU项目Linux内核的创建 Linux的特点开放源代码多样性社区支持 Linux的应用服务器和超级计算机嵌入式系统桌面系统 总结 操作系统发展历史 操作系统&#xff08;Operating System&am…

详细教程 - 从零开发 Vue 鸿蒙harmonyOS应用 第五节 (基于uni-app封装鸿蒙接口请求库)

随着鸿蒙系统的兴起,越来越多的app会采用鸿蒙开发。而鸿蒙开发必不可少的就是调用各种接口服务。为了简化接口的调用流程,我们通常会做一层封装。今天就来讲解一下,如何用uni-app封装鸿蒙的接口请求库。 一、新建项目 首先我们要新建一个鸿蒙项目啦&#xff01;当然选择第一个…

neuq-acm预备队训练week 9 P1119 灾后重建

解题思路 本题可以用最短路算法——Floyd AC代码 #include<bits/stdc.h> #define inf 1e9 using namespace std; const int N 2e2 50; int n, m, q, now 0, a, b, c, t[N], G[N][N];int main() {scanf("%d%d", &n, &m);for(int i 0;i<n;i)sc…

044.Python异常处理_手动抛出异常自定义异常

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

ubuntu 磁盘挂载

1.前提 给自己的计算机加了一个新硬盘&#xff0c;怎么在ubuntu中使用呢 特别提示&#xff01;对磁盘操作存在一定丢失数据的风险&#xff0c;本篇是在一个新购买的硬盘上进行操作&#xff01;如果你使用的是一个带数据的硬盘&#xff0c;请勿参考本篇文章&#xff01; 2.找…

解决:AttributeError: module ‘scipy.misc’ has no attribute ‘imread’

解决&#xff1a;AttributeError: module ‘scipy.misc’ has no attribute ‘imread’ 文章目录 解决&#xff1a;AttributeError: module scipy.misc has no attribute imread背景报错问题报错翻译报错位置代码报错原因解决方法方法一 scipy版本回退&#xff08;不推荐&#…

记录 | Visual Studio报错:const char*类型的值不能用于初始化char*类型

Visual Studio 报错&#xff1a; const char *”类型的值不能用于初始化“char *”类型的实体错误 解决办法&#xff1a; 1&#xff0c;强制类型转换&#xff0c;例如&#xff1a; char * Singer::pv[] {(char*)"other", (char*)"alto", (char*)"c…

会旋转的树,你见过吗?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

工业数据的特殊性和安全防护体系探索思考

随着工业互联网的发展&#xff0c;工业企业在生产运营管理过程中会产生各式各样数据&#xff0c;主要有研发设计数据、用户数据、生产运营数据、物流供应链数据等等&#xff0c;这样就形成了工业大数据&#xff0c;这些数据需要依赖企业的网络环境和应用系统进行内外部流通才能…

字体包引入以及使用

将UI给的字体包下载到assets文件夹下 app.vue全局定义 <style> * {margin: 0;padding: 0; }font-face {font-family: PangMenZhengDao-3;src: url(/assets/fonts/庞门正道标题体3.0.TTF) format(truetype);font-weight: bold;font-style: normal; } </style>页面使…