1. 基本概念和架构

1.1 基本介绍

Kubernetes,简称K8S。一款开源、用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署、规划、更新、维护的一种机制。

传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。

新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。

容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在 build 或 release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更 “透明”,这更便于监控和管理。

Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。

在 Kubernetes 中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。

※ 发展经历

经典案例:

Infrastructure as a Service(阿里云)

Platform as a service(新浪云)

Software as a Service(Office 365)


集群资源管理器:

Apache MESOS(最新版本可以管理Kubernetes, 但增加软件层可能会增加故障节点)

  • Apache开源协议,分布式资源管理框架。
  • 2019年5月,Twitter弃用 MESOS,开始使用Kubernetes。

Docker Swarm(功能较少, 缺乏滚动更新+回滚等功能)

  • 2019年7月,阿里云宣布删除 Docker Swarm 选项。

Kubernetes(Google)

  • Google拥有10年容器化基础架构经验,Google拥有强大的内部的容器管理系统——Borg。
  • 采用GO语言,借鉴Borg的思想,开发了Kubernetes。
  • 特点:
  • 轻量级:消耗资源小
  • 开源
  • 弹性伸缩
  • 负载均衡:IPVS框架

  • K8S是谷歌在2014年开源的容器化集群管理系统。
  • 使用K8S进行容器化应用部署。
  • 使用K8S利于应用扩展。
  • K8S目标:让部署容器化应用更加简介、高效。

1.2 功能和架构

1.2.1 概述

Kubernetes 是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环境运行工作负载15年的经验,并吸收了来自于社区的最佳想法与实践。

1.2.2 功能

  • 自动装箱
    基于容器对应用运行环境的资源配置要求自动部署应用容器。
  • 自我修复(自愈能力)
    当容器失败时,会对容器进行重启。
    当所部署的 Node 节点有问题时,会对容器进行重新部署、重新调度。
    当容器未通过监控检查时,会关闭此容器。直到容器正常运行时,才会对外提供服务。
  • 水平扩展
    通过简单的命令、用户UI界面或基于CPU等资源的使用情况,对应用容器进行规模扩大或规模剪裁。
  • 服务发现
    用户无需使用额外的服务发现机制,就能基于 Kubernetes 自身能力实现服务发现和负载均衡。
  • 滚动更新
    可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新。
  • 版本回退
    可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退。
  • 密钥和配置管理
    在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
  • 存储编排
    启动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要。
    存储系统可以来自于本地目录、网络存储(NFS、Gluster、Ceph等)、公共云存储服务。
  • 批处理
    提供一次性任务,定时任务;满足批量数据处理和分析场景。

1.2.3 K8S集群架构组件

  • Master(主控节点)
  • API Server:集群的统一入口,以RESTful方式,交给etcd存储
  • Scheduler:节点调度,选择node节点应用部署
  • controller-manager:处理集群中常规后台任务,一个资源对应一个控制器
  • etcd:存储系统,用于保存集群相关数据
  • Node(工作节点)
  • Kubelet:Master派到Node节点代表,管理本机容器
  • Kube-Proxy:提供网络代理、负载均衡等操作

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署

① Master Node

K8S集群控制节点,对集群进行调度管理,接受集群外用户去集群操作请求;Master Node 由 API Server、Scheduler、ClusterState Strore(ETCD数据库)和 Controller ManagerServer所组成。

② Worker Node

集群工作节点,运行用户业务应用容器;

Worker Node 包含 kubelet、kube proxy 和 ContainerRuntime;

confluence容器化部署 kubernetes如何简化容器化部署_k8s_02

1.2.4 核心概念

① Pod
  • 最小部署单元
  • 一组容器的集合
  • 共享网络
  • 生命周期短暂
② Controller
  • 确保预期的Pod副本数量
  • 应用部署状态
  • 无状态应用部署
  • 有状态应用部署 (依赖存储 / IP唯一)
  • 确保所有的Node运行同一个Pod
  • 一次性任务、定时任务
③ Service
  • 定义一组Pod访问规则

confluence容器化部署 kubernetes如何简化容器化部署_容器_03

2. 搭建集群

2.1 搭建K8S环境平台规划

2.1.1 单Master集群

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_04

2.1.2 多Master集群

confluence容器化部署 kubernetes如何简化容器化部署_k8s_05

2.2 服务器硬件配置要求

2.2.1 测试环境

Master:CPU 2核、内存4GB、磁盘20GB

Node:CPU 4核、内存8GB、磁盘40GB

2.2.2 生产环境

Master:CPU 8核+、内存16GB+、磁盘100GB+

Node:CPU 16核+、内存64GB+、磁盘500GB+

2.3 搭建K8S集群部署方式

目前生产部署 Kubernetes 集群主要有两种方式:

  • Kubeadm
  • 二进制包
  • 从Github再在发行版的二进制包,手动部署每个组件,组成 Kubernetes 集群。
  • Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易控制,推荐使用二进制包部署 Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。

2.4 Kubeadm部署方式

Kubeadm 是官方社区推出的一个用于快速部署 Kubernetes 集群的工具,这个工具能通过两条指令完成一个 Kubernetes 集群的部署:

  1. 创建一个Master节点:kubeadm init
  2. 将Node节点加入到当前集群中 kubeadm join <Master 节点IP和端口>

2.4.1 安装要求

在开始之前,部署 Kubernetes 集群及其需要满足以下几个条件:

  • 一台/多台机器,操作系统 CentOS7.x-86_x64
  • 硬件配置:内存2GB+,CPU 2+、硬盘30GB+
  • 集群中所有机器之间网络互通
  • 可以访问外网,需要拉取镜像
  • 禁止 swap 分区

2.4.2 最终目标

  1. 在所有节点上安装Docker和Kubeadm
  2. 部署 Kubernetes Master
  3. 部署容器网络插件
  4. 部署 Kubernetes Node,将节点加入Kubernetes 集群中
  5. 部署Dashboard Web 页面,可视化查看Kubernetes 资源

2.4.3 准备环境

① 虚拟机准备

角色

IP

K8S-Master

192.168.1.136

K8S-Node1

192.168.1.135

K8S-Node2

192.168.1.134

② 系统初始化

1、关闭防火墙

$ systemctl stop firewalld		# 临时
$ systemctl disable firewalld 	# 永久

2、关闭 selinux

$ sed -i 's/enforcing/disabled/' /etc/selinux/config 	# 永久
$ setenforce 0		# 临时

3、关闭 swap

$ swapoff -a		# 临时
$ vim /etc/fstab	# 永久(删除swap相关行 /mnt/swap swap swap defaults 0 0 这一行或者注释掉这一行)
$ free -m				# 确认swap已经关闭(若swap行都显示 0 则表示关闭成功)

4、根据规划设置主机名

$ hostnamectl set-hostname <hostname>

5、在master添加hosts

$ cat >> /etc/hosts << EOF
192.168.1.136 k8smaster
192.168.1.135 k8snode1
192.168.1.134 k8snode2
EOF

6、将桥接的IPv4流量传递到iptables的链

$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system		# 生效

7、时间同步

$ yum install ntpdate -y
$ ntpdate time.windows.com

2.4.4 所有节点安装Docker/Kubeadm/Kubelet

Kubernetes 默认CRI(容器运行时)为Docker,因此先安装Docker。

① 安装Docker
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.el7
$ systemctl enable docker && systemctl start docker
$ docker --version
Docker version 18.06.1-ce, build e68fc7a
$ cat > /etc/docker/daemon.json << EOF
{
	"registry-mirrors":["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
② 添加阿里云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
③ 安装 Kubeadm、Kubelet、Kubectl

由于版本更新频繁,这里指定版本号部署:

$ yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
$ systemctl enable kubelet

2.4.5 部署 Kubernetes Master

在Master中执行命令:

$ kubeadm init \
 --apiserver-advertise-address=192.168.1.136 \
 --image-repository registry.aliyuncs.com/google_containers \
 --kubernetes-version v1.18.0 \
 --service-cidr=10.96.0.0/12 \
 --pod-network-cidr=10.244.0.0/16

由于默认拉区镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_06

使用kubectl工具(省略权限修饰符):

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

查看当前已加入节点:

kubectl get nodes

此时,各个节点状态为Not Ready。

2.4.6 加入 Kubernetes Node

在Node执行命令,向集群添加新节点,执行在kubeadm init输出的kubeadm join命令:

kubeadm join 192.168.1.136:6443 --token 3o69uv.pugf6vy6lq44wjrs \
    --discovery-token-ca-cert-hash sha256:3150067383e9af1021776982a4100823564e7ab0a604fe59137409159042b9ec

默认token有效期为24小时,当过期后,该token就不可用了。这时就需要重新创建token,操作如下:

kubeadm token create --print-join-command

2.4.7 部署CNI网络插件

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

默认镜像地址无法访问,sed命令修改为docker hub 镜像仓库。(连接不上可查询IP并修改/etc/hosts文件)

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubectl get pods -n kube-system

confluence容器化部署 kubernetes如何简化容器化部署_k8s_07

查看当前已加入节点:

kubectl get nodes

此时,各个节点状态为Ready。

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_08

2.4.8 测试 Kubernetes 集群

在Kubernetes集群中创建一个pod,验证是否正常运行:

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc

访问地址:http://Node_IP:Port

confluence容器化部署 kubernetes如何简化容器化部署_容器_09

confluence容器化部署 kubernetes如何简化容器化部署_k8s_10

3. Kubernetes集群命令行工具kubectl

3.1 概述

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

3.2 kubectl命令的语法

kubectl [command] [TYPE] [NAME] [flags]
  • command:指定要对资源执行的操作,例如create、get、describe、delete等
  • TYPE:指定资源类型,资源类型是大小写敏感的,开发者能够以单数、复数、缩略形式。
kubectl get pod pod1
kubectl get pods pod1
kubectl get po pod1
  • NAME:指定资源的名称,名称也大小写敏感。如果省略名称,则会显示所有的资源。例如:
kubectl get pods
kubectl get nodes
  • flags:指定可选的参数。例如:可用-s或者-server参数指定 Kubernetes API server 的地址、端口。

3.3 kubectl --help 获取更多信息

所有帮助信息:

kubectl --help

confluence容器化部署 kubernetes如何简化容器化部署_k8s_11

具体查看某个操作帮助信息:

kubectl [?] --help

3.4 kubectl 子命令使用分类

3.4.1 基础命令

命令

解释

create

通过文件或标准输入创建资源

expose

将一个资源公开为一个新的Service

run

在集群中运行一个特定的镜像

set

在对象上设置特定的功能

get

显示一个/多个资源

explain

文档参考资料

edit

使用默认的编辑器编辑一个资源

delete

通过文件名、标准输入、资源名称、标签选择器来删除资源

3.4.2 部署和集群管理命令

① 部署命令

命令

解释

rollout

管理资源的发布

rolling-update

给指定的复制控制器滚动更新

scale

扩容/缩容Pod数量,Deployment、ReplicaSet、RC、Job

autoscale

创建一个自动选择扩容/缩容并设置Pod数量

② 集群管理命令

命令

解释

certificate

修改证书资源

cluster-info

显示集群信息

top

显示资源(CPU/Memory/Storage)使用。需要Heapster运行。

cordon

标记节点不可调度

uncordon

标记节点可调度

drain

驱逐节点上的应用,准备下线维护

taint

修改节点taint标记

3.4.3 故障和调试命令

命令

解释

describe

显示特定资源或资源组的详细信息

logs

在一个Pod中打印一个容器日志,如果Pod只有一个容器,容器名称是可选的

attach

附加到一个运行的容器

exec

执行命令到容器

port-forward

转发一个/多个本地端口到一个Pod

proxy

运行一个proxy到Kubernetes API Server

cp

拷贝文件/目录到容器中

auth

检查授权

3.4.5 其他命令

① 高级命令

命令

解释

apply

通过文件名/标准输入对资源应用配置

patch

使用补丁修改、更新资源的字段

replace

通过文件名/标准输入替换一个资源

convert

不同的API版本之间转换配置文件

② 设置命令

命令

解释

label

更新资源上的标签

annotate

更新资源上的注释

completion

用于实现kubectl工具自动补全

③ 其他命令

命令

解释

api-versions

打印受支持的API版本

config

修改kubeconfig文件(用于访问API,比如配置认证信息)

help

所有命令帮助

plugin

运行一个命令行插件

version

打印客户端和服务版本信息

※ 常用命令举例

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
kubectl get pods
kubectl get nodes
kubectl cs
kubectl apply -f [yaml文件本地/网络路径]

4. 资源编排:YAML

4.1 介绍

K8S集群中对资源管理和资源对象编排部署都可以通过声明样式(YAML)文件来解决,也就是可以把需要对资源对象操作编辑到YAML格式文件中,我们把这种文件叫做资源清单文件,通过kubectl命令直接使用资源清单文件就可以实现对大量的资源对象进行编排部署了。

4.2 编写格式

4.2.1 YAML介绍

YAML:仍是一种标记语言。为了强调这种语言以数据作为中心,而不是以标记语言作为重点。

YAML是一个可读性高,用来表达数据序列的格式。

4.2.2 YAML基本语法

  • 使用空格作为缩进,通过缩进表示层级关系
  • 缩进空格数目不重要,只要相同层级的元素左侧对齐即可
  • 一般缩进不允许使用Tab键,只允许使用空格
  • 一般开头缩进两个空格,字符 (冒号/逗号) 后缩进一个空格
  • 使用---表示新的yaml文件开始
  • 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略

4.2.3 YAML文件组成

  • 控制器定义
  • 被控制对象
# 控制器定义
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
# 被控制对象
    template: 		# 开始定义规则
      metadata:
        labels:
          app: nginx
      spec:
       containers:
       - name: nginx
         image: nginx:latest
         ports:
         - containerPort: 80

4.2.4 YAML常用字段含义

字段

含义

apiVersion

API版本

kind

资源类型

metadata

资源元数据

spec

资源规格

replicas

副本数量

selector

标签选择器

template

Pod模板

metadata

Pod元数据

spec

Pod规格

containers

容器配置

4.2.5 快速编写YAML文件

  • 使用 kubectl create 命令生成 YAML文件
  • 使用 kubectl get 导出 YAML文件
① 使用kubectl create命令生成文件

举例:

产生yaml格式:

kubectl create deployment web --image=nginx -o yaml --dry-run

输出至具体文件:

kubectl create deployment web --image=nginx -o yaml --dry-run > m1.yaml
② 使用 kubectl get 导出 YAML文件

举例:

从已部署资源中导出yaml,并输出至文件:

kubectl get deploy nginx -o=yaml --export > m2.yaml

5. 核心概念

5.1 Pod

5.1.1 Pod 概述

Pod是K8S系统中可以创建、管理的最小单元,是资源对象模型中由用户创建/部署的最小资源对象模型,也是在K8S上运行容器化应用的资源对象,其他资源对象都是用来支撑/扩展Pod对象功能的,比如Controller对象是用来管控Pod对象的,Service/Ingress资源对象是用来暴露Pod引用对象的,Persistent Volumn 资源对象是用来为Pod提供存储等等,K8S不会直接处理容器,而是Pod。Pod是由一个/多个container组成。

Pod是 Kubernetes 的最重要概念,每一个Pod都有一个特殊的被称为 “根容器” 的 Pause容器。Pause容器对应的镜像属于 Kubernetes 平台的一部分,除了Pause容器,每个Pod还包含一个/多个紧密相关的用户业务容器。

confluence容器化部署 kubernetes如何简化容器化部署_容器_12

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_13


特点总结:

  • 最小部署单元
  • 包含多个容器(一组容器的集合)
  • 一个Pod中的容器共享网络命名空间
  • Pod是短暂的

存在意义:

  • 创建容器使用Docker,一个Docker对应一个容器,一个容器有进程 (查看进程ps -ef),一个容器运行一个应用程序(单进程+守护进程)
  • Pod是多进程设计,运行多个应用程序(一个Pod有多个容器,一个容器里运行一个应用程序)
  • Pod的存在为了 亲密性应用 而产生
  • 两个应用之间进行交互
  • 网络之间调用 (127.0.0.1 / Socket)
  • 两个应用需要频繁调用

5.1.2 Pod 实现机制

Pod 两大实现机制:

  • 共享网络
  • 共享存储
① 共享网络

容器本身之间相互隔离

  • namespace
  • group

前提条件:容器在同一个namespace中


实现机制:

通过Pause容器,把其他业务容器加入Pause容器,让所有容器在同一个namespace中,实现网络共享。

  • 首先,创建Pause容器(独立IP、MAC、Port、namespace)
  • 其次,分别创建业务容器并加入Pause容器,使其处于同一namespace中
② 共享存储

Pod持久化操作:

  • 日志数据
  • 业务数据

引入数据卷概念Volumn,使用数据卷进行持久化存储。

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_14


示例YAML:

confluence容器化部署 kubernetes如何简化容器化部署_容器_15

5.1.3 Pod 镜像拉取策略

Pod镜像拉取策略 imagePullPolicy:

  • IfNotPresent:镜像在宿主机上不存在时才拉取(默认)
  • Always:每次创建Pod都会重新拉取一次镜像
  • Never:Pod永远不会主动拉取这个镜像

示例:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
   - name: nginx
     image: nginx:1.14
     imagePullPolicy: Always

# Pod镜像拉取策略-imagePullPolicy
# IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
# Always:每次创建Pod都会重新拉取一次镜像
# Never:Pod永远不会主动拉取这个镜像

5.1.4 Pod 资源限制

confluence容器化部署 kubernetes如何简化容器化部署_docker_16

示例:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
   - name: db
     image: mysql
     env:
     - name: MYSQL_ROOT_PASSWORD
       value: "password"
      
     resources:
       requests:		# 资源请求(调度)
         memory: "64Mi"
         cpu: "250m"
      
      limits:		# 资源限制(最大)
        memory: "128Mi"
        cpu: "500m"

Pod和Container的资源请求和限制:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory

CPU资源举例解释:设 1c=1000m,则0.25c=250m、0.5=500m


5.1.5 Pod 重启机制

Pod重启机制 restartPolicy:

  • Always:当容器终止退出后,总是重启容器(默认)
  • OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
  • Never:当容器终止退出,从不重启容器
  • 批量一次性任务正常结束

示例:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: busybox
    image: busybox:1.28.4
    args: 
    - /bin/sh
    - -c
    - sleep 36000
  restartPolicy: Never

# Pod重启机制-restartPolicy
# Always:当容器终止退出后,总是重启容器,默认策略
# OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
# Never:当容器终止退出,从不重启容器

5.1.6 Pod 健康检查

应用层面健康检查:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: liveness
    image: busybox
    args: 
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy
    livenessProbe: 
      exec:
       command:
       - cat
       - /temp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

健康检查策略:

  • livenessProbe(存活检查)
    如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
  • readinessPribe(就绪检查)
    如果检查失败,Kubernetes会把Pod从service endpoints中剔除。

Porbe支持的检查方法:

  • httpGet
    发送HTTP请求,返回200~400范围状态码为成功。
  • exec
    执行shell命令返回状态码是0为成功。
  • touch创建文件后,通过echo $?查看状态码为0;删除文件后,通过echo $?查看状态码为1。
  • tcpSocket
    发起TCP Socket建立成功

5.1.7 Pod 调度策略

confluence容器化部署 kubernetes如何简化容器化部署_docker_17

① 创建Pod流程

confluence容器化部署 kubernetes如何简化容器化部署_k8s_18

master节点:

  • createpod – apiserver – etcd
  • scheduler – apiserver – etcd – 调度算法, 将Pod调度到Node节点

node节点:

  • kubelet – apiserver – 读取etcd拿到分配给当前节点pod – docker创建容器
② Pod调度

影响调度的属性:

  • Pod资源限制
    根据request找到足够node节点进行调度。
  • 节点选择器nodeSelector标签
    (对节点创建标签:kubectl label [node_name] env_role=dev
apiVersion: v1
kind: Pod
metadata: 
  name: pod-example
spec: 
  nodeSelector:
    env_role: dev
  containers:
  - name: nginx
    image: nginx:1.15

confluence容器化部署 kubernetes如何简化容器化部署_k8s_19

  • 节点亲和性nodeAffinity标签
    与nodeSelector基本一样,根据节点上标签的约束来决定Pod调度到哪些节点上,但功能更加强大。
  • 硬亲和性(requiredDuringSchedulingIgnoreDuringExecution):约束条件必须满足
  • 软亲和性(preferredDuringSchedulingIgnoreDuringExecution):尝试满足,不保证绝对满足
apiVersion: v1
kind: Pod
metadata: 
  name: with-node-affinity
spec: 
  affinity:
    nodeAffinity: 
    requiredDuringSchedulingIgnoreDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: evn_role
          operator: In
          values:
          - dev
          - test
    preferredDuringSchedulingIgnoreDuringExecution:
    - weight: 1
      preference:
       matchExpressions: 
        - key: group
          operator: In
          values:
          - otherprod
  containers:
  - name: webdemo
    image: nginx

支持常用操作符operator:In、NotIn(反亲和性)、Exists、Gt、Lt、DoesNotExists(反亲和性)

  • 污点&污点容忍
  • 基本介绍:
  • nodeSelector、nodeAffinity:Pod调度到节点上,Pod属性,调度时实现。
  • Taint污点:节点不做普通分配调度,是节点属性
  • 场景:
  • 专用节点(IP范围)
  • 配置特定硬件节点
  • 基于Taint驱逐
  • 具体演示:
  • 查看节点污点情况:kubectl describe node [node_name] | grep Taint污点值(taint_value)有三个:
  • NoSchedule:一定不被调度
  • PreferNoSchedule:尽量不被调度
  • NoExecute:不会调度,并且驱逐已有Pod进其它Node
  • 为节点添加污点 (key, value自定义):kubectl taint node [node_name] key=value:[taint_value]
  • 为节点删除污点 (key, value自定义):kubectl taint node [node_name] key=value-
  • 污点容忍tolerations : 可能被调度 (部分YAML) :
spec: 
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
  containers:
  - name: webdemo
    image: nginx

5.2 Controller

5.2.1 Controller概述

  • 在集群上,管理和运行容器的对象

5.2.2 Pod和Controller关系

  • Pod通过Controller实现应用的运维
    (如:伸缩、滚动升级 等)
  • Pod与Controller之间通过 label标签 建立关系

confluence容器化部署 kubernetes如何简化容器化部署_k8s_20

5.2.3 Deployment控制器应用场景

  • 部署无状态应用
  • 管理Pod和ReplicaSet
  • 部署、滚动升级 等功能

应用场景:Web服务、微服务

5.2.4 Deployment:控制器部署无状态应用

  • 导出yaml文件:kubectl create deployment web --image=nginx --dry-run -o yaml > web.yaml

confluence容器化部署 kubernetes如何简化容器化部署_docker_21

  • 使用yaml部署应用:kubectl apply -f web.yaml;并查看状态:kubectl get pods

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_22

  • 对外发布(暴露对外端口号):kubectl expose deployment [app_name] --port=80 --type=NodePort --target-port=80 --name=[app_name]

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_23

5.2.5 应用升级回滚

① 应用升级

升级应用至某指定版本:

kubectl set image deployment web [the_name]=[image_name]:[version_number]

# 举例
kubectl set image deployment web nginx=nginx:1.15

查看升级状态:

confluence容器化部署 kubernetes如何简化容器化部署_docker_24

② 应用回滚

查看应用升级历史版本:

confluence容器化部署 kubernetes如何简化容器化部署_docker_25


回滚至上一个版本:

kubectl rollout undo deployment web

查看回滚状态:

kubectl rollout status deployment web

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_26


回滚到指定版本(eg. 1):

kubectl rollout undo deployment web --to-revision=1

confluence容器化部署 kubernetes如何简化容器化部署_k8s_27

5.2.6 应用弹性伸缩

提供更多服务:

kubectl scale deployment web --replicas=10

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_28

查看新增9个副本:

confluence容器化部署 kubernetes如何简化容器化部署_k8s_29

5.2.7 StatefulSet:部署有状态应用

※ 无状态 & 有状态:
  • 无状态
  • 认为Pod都是一样的
  • 没有顺序要求
  • 不用考虑在哪个Node运行
  • 随意进行伸缩、扩展
  • 有状态
  • 考虑以上所有因素
  • 让每个Pod独立,保持Pod的启动顺序、唯一性
  • 唯一的网络标识符、持久存储
  • 有序(如:MySQL主从)
  • 无头Service
  • ClusterIP:none
※ 部署有状态应用

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
metadata: 
  name: nginx-statefulset
  namespace: default
spec: 
  serviceName: nginx
  replicas: 3
  selector: 
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

confluence容器化部署 kubernetes如何简化容器化部署_k8s_30

查看Pod,有3个Pod,每个都是唯一名称:

confluence容器化部署 kubernetes如何简化容器化部署_k8s_31

查看创建的无头Service:

confluence容器化部署 kubernetes如何简化容器化部署_容器_32


Deployment 和 StatefulSet区别:有身份(唯一标识):

  • 根据主机名(每个Pod有唯一主机名) + 按照一定规则生成域名
  • 每个Pod有唯一主机名
  • 生成唯一域名:
  • 主机格式.service名称.名称空间.svc.cluster.local
  • 举例:nginx-statfulset-0.nginx.default.svc.cluster.local

5.2.8 DeamonSet:部署守护进程

部署守护进程DeamonSet

  • 在每个node节点上运行同一个Pod,新加入的node也同样运行这个Pod
  • 举例:每个node节点安装数据采集工具

YAML示例:

apiVersion: apps/v1
kind: DaemonSet
metadata: 
  name: ds-test
  labels: 
    app: filebeat
spec: 
  selector:
    matchLabels: 
      app: filebeat
  template: 
    metadata:
      labels:
        app: filebeat
    spec:
      containers:
      - name: logs
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts: 
        - name: varlog
          mountPath: /tmp/log
      volumes:
      - name: varlog
        hostPath: 
          path: /var/log

创建成功:

confluence容器化部署 kubernetes如何简化容器化部署_容器_33

confluence容器化部署 kubernetes如何简化容器化部署_容器_34

进入其中一个Pod (kubectl exec -it [pod_name] bash),查看日志文件:

confluence容器化部署 kubernetes如何简化容器化部署_容器_35

5.2.9 Job:部署一次任务

YAML示例:

apiVersion: batch/v1
kind: Job
metadata: 
  name: pi
spec: 
  template: 
    spec: 
      containers:
      - name: pi
        image: perl
        command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4   # 失败后尝试重试次数

创建成功 (kubectl create -f pi.yaml):

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_36

计算完成:

confluence容器化部署 kubernetes如何简化容器化部署_k8s_37

通过日志(kubectl logs pi-gxztq),查看计算结果:

confluence容器化部署 kubernetes如何简化容器化部署_容器_38

通过删除K8S中缓存的yaml文件,移除一次性任务:

confluence容器化部署 kubernetes如何简化容器化部署_k8s_39

5.2.10 CronJob:部署定时任务

YAML示例:

apiVersion: batch/v1beta1
kind: CronJob
metadata: 
  name: hello
spec: 
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args: 
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

创建成功:

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_40

已成功运行一次:

confluence容器化部署 kubernetes如何简化容器化部署_容器_41

通过日志,查看运行结果:

confluence容器化部署 kubernetes如何简化容器化部署_docker_42

每隔一段时间执行一次,出现一个Pod (Complated):

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_43

删除K8S缓存yaml配置,移除定时任务:

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_44

5.3 Service

5.3.1 存在意义

  • Pod的IP不固定,Service可防止Pod失联(服务发现)
  • 定义一组Pod访问策略(负载均衡)

5.3.2 Pod和Service关系

根据 label 和 selector 标签建立关联

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_45

通过Service实现Pod的负载均衡,每个Service拥有一个 虚拟IP(Virtual IP),借助Service访问一组Pod通过虚拟IP访问。

confluence容器化部署 kubernetes如何简化容器化部署_k8s_46

5.3.3 常用Service类型

  • ClusterIP:集群内部访问
  • NodePort:对外访问应用使用
  • LoadBalancer:对外访问应用使用 / 用于公有云
  • ExternalName:将服务映射到 DNS 名称,而非典型的选择器(需追加属性externalName)
type: ExternalName
externalName: [external_name]
① ClusterIP

使用kubectl expose deployment web --port=80 --target-port=80 --dry-run -o yaml > service.yaml导出web的svc(Service)配置,并进行修改:

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_47

使用命令kubectl apply -f service.yaml执行(若已自动生成svc, 可手动删除替换),创建Service:

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_48

从其他节点内部访问curl [ip_address]

confluence容器化部署 kubernetes如何简化容器化部署_k8s_49

② NodePort

更改名称并更改类型为NodePort:

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_50

创建成功,检查类型:

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_51

内部访问成功:

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_52

外部访问成功:

confluence容器化部署 kubernetes如何简化容器化部署_容器_53

③ LoadBalancer

Node在内网进行部署,外网一般不能访问到:

  • 找到一台可以进行外网访问机器,安装nginx,反向代理
  • 手动把可以访问到的节点添加到nginx里
  • LoadBalancer:公有云 → 负载均衡、控制器

5.4 配置管理

5.4.1 Secret

作用:加密数据存在etcd中,让Pod容器以挂载 变量/Volume(数据卷) 方式进行访问

场景:凭证

  • base64编码 (echo -n [target_str] | base64)

  1. 创建Secrete加密数据(用户名密码已用base64加密, 命令kubectl create -f secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

confluence容器化部署 kubernetes如何简化容器化部署_docker_54

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_55

  1. 以变量形式挂载到Pod容器中
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec: 
  containers:
  - name: nginx
    image: nginx
    env:
    - name: SECRET_USERNAME
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: username
    - name: SECRET_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: password

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_56

confluence容器化部署 kubernetes如何简化容器化部署_docker_57

  1. 以Volume(数据卷)形式挂载到Pod容器中
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec: 
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes: 
  - name: foo
    secret: 
      secretName: mysecret

confluence容器化部署 kubernetes如何简化容器化部署_k8s_58

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_59

5.4.2 ConfigMap

作用:存储不加密数据到etcd中,让Pod以变量或Volume数据卷形式挂载到容器中

场景:配置文件 (IP / 端口号 / 用户名)


  1. 创建配置文件(如:Redis配置文件)
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
  1. 创建configMap (命令:kubectl create configmap redis-config --from-file=redis.properties)

查看所有kubectl get configmapkubectl get cm,查看详细信息kubectl describe cm redis-config

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_60

  1. 以Volume挂载到Pod容器(cm.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec: 
  containers:
  - name: busybox
    image: busybox
    command: [ "/bin/sh","-c","cat /etc/config/redis.properties" ]
    volumeMounts:
    - name: config-volume
      mountPath: "/etc/config"
  volumes: 
  - name: config-volume
    configMap: 
      name: redis-config
  restartPolicy: Never

confluence容器化部署 kubernetes如何简化容器化部署_k8s_61

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_62

  1. 以变量形式挂载到Pod容器(myconfig.yaml)
    ① 创建yaml,声明变量信息 configmap 创建 kubectl apply -f myconfig.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfig
  namespace: default
data:
  special.level: info
  special.type: hello

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_63

② 以变量挂载(config-var.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec: 
  containers:
  - name: busybox
    image: busybox
    command: [ "/bin/sh","-c","echo $(LEVEL) $(TYPE)" ]
    env:
    - name: LEVEL
      valueFrom:
        configMapKeyRef:
          name: myconfig
          key: special.level
    - name: TYPE
      valueFrom:
        configMapKeyRef:
          name: myconfig
          key: special.type
  restartPolicy: Never

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_64

通过日志查看输出:

confluence容器化部署 kubernetes如何简化容器化部署_docker_65

5.5. 集群安全机制

5.5.1 概述

  • 访问K8S集群资源(Pod/Service/Controller)时,需要经过三个步骤完成具体操作
  • 第一步:认证
  • 第二步:鉴权(授权)
  • 第三步:准入控制
  • 进行访问时,过程中需要经过 API Server 做统一协调。
  • 访问过程中,需要证书 / token / 用户名+密码。
  • 访问Pod需要serviceAccount。
① 认证:传输安全
  • 传输安全:对外不暴露8080端口,只能内部访问,对外使用端口6443
  • 认证:客户端身份认证常用方式:
  • https证书认证:基于CA证书
  • http token:通过token识别用户
  • http基本认证:用户名+密码认证
② 鉴权 (授权)
  • 基于RBAC鉴权操作
  • 基于角色访问控制
③ 准入控制
  • 进入准入控制器的列表,如果列表中有请求内容就通过,如果没有就拒绝

5.5.2 RBAC介绍

基于角色的访问控制

  • 角色
  • role:特定命名空间访问权限(查看命名空间:kubectl get ns
  • clusterRole:所有命名空间控制
  • 角色绑定
  • roleBingding:角色绑定到主体
  • clusterRoleBingding:集群的角色绑定到主体
  • 主体:
  • user:用户
  • group:用户组
  • serviceAccount:服务账号(Pod访问)

confluence容器化部署 kubernetes如何简化容器化部署_k8s_66

5.5.3 RBAC鉴权

  1. 创建命名空间
  2. 在新创建的命名空间创建一个Pod
  3. 创建角色(rbac-role.yaml)
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: roledemo
  name: pod-reader
rules: 
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

confluence容器化部署 kubernetes如何简化容器化部署_k8s_67

查看角色:

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_68

  1. 创建角色绑定(rbac-rolebinding.yaml)
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: roledemo
  name: read-pods
subjects: 
- kind: User
  name: lucy  # Name is case sensive
  apiGroup: rbac.authorization.k8s.io
roleRef: 
  kind: Role  # This must be Role or ClusterRole
  name: pod-reader  # This must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io

confluence容器化部署 kubernetes如何简化容器化部署_k8s_69

confluence容器化部署 kubernetes如何简化容器化部署_docker_70

  1. 使用证书识别身份(二进制搭建集群)
cat > lucy-csr.json << EOF
{
  "CN": "lucy",
  "host": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes lucy-csr.json | cfssljson -bare lucy

kubectl config set-cluster kubernetes \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://192.168.1.1.36:6443 \
  --kubeconfig=lucy-kubeconfig

kubectl config set-certificate lucy \
  --client-key=lucy-key.pem \
  --client.certificate=lucy.pem \
  --embed-certs=true \
  --kubeconfig=lucy-kubeconfig

kubectl config set-context lucy \
  --cluster=kubernetes \
  --user=lucy \
  --kubeconfig=lucy-kubeconfig
  
kubectl config use-context default --kubeconfig=lucy-kubeconfig

5.6 Ingress

5.6.1 概述

  • 把端口号对外暴露,通过IP+端口号进行访问
  • 使用Service中NodePort实现
  • NodePort缺陷
  • 在每个节点上都会启动端口,在访问时通过任何节点IP+暴露端口号进行访问
  • 意味着每个端口只能使用一次,一个端口对应一个项目
  • 实际访问中都是使用域名,根据不同域名跳转到不同端口服务中
  • Ingress和Pod关系
  • pod和ingress通过service关联
  • ingress作为统一入口,由service关联一组pod
  • Ingress工作流程
  • 使用Ingress
  • 部署Ingress Controller (官方维护nginx控制器→实现部署)
  • 创建Ingress规则

confluence容器化部署 kubernetes如何简化容器化部署_k8s_71

5.6.2 对外暴露应用

  1. 创建nginx-pod应用,对外暴露端口使用NodePort

confluence容器化部署 kubernetes如何简化容器化部署_k8s_72

  1. 部署 Ingress Controller
apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses/status
    verbs:
      - update

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      hostNetwork: true
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        kubernetes.io/os: linux
      containers:
        - name: nginx-ingress-controller
          image: lizhenliang/nginx-ingress-controller:0.30.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 101
            runAsUser: 101
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown

---

apiVersion: v1
kind: LimitRange
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  limits:
  - min:
      memory: 90Mi
      cpu: 100m
    type: Container

confluence容器化部署 kubernetes如何简化容器化部署_容器_73

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_74

  1. 创建ingress规则
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.ingredemo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 80

confluence容器化部署 kubernetes如何简化容器化部署_docker_75

confluence容器化部署 kubernetes如何简化容器化部署_容器_76

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_77

  1. 在windows系统host文件(C:\Windows\System32\drivers\etc\hosts)中添加域名访问规则后,并访问

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_78

5.7 Helm

5.7.1 引入

此前部署应用的过程:

  • 编写yaml文件
  • Deployment
  • Service
  • Ingress

如果使用此前的方式 部署 单一应用/少数服务的应用 比较合适。

部署微服务项目,可能会有几十个服务,每个服务都有一套yaml文件,需要维护大量yaml文件,版本管理不方便。


使用helm可以解决哪些问题?

  • 使用helm可将这些yaml文件作为一个整体管理
  • 实现yaml文件高效复用
  • 实现应用级别的版本管理

5.7.2 概述

Helm介绍:

Helm是个Kubernetes的包管理工具,就想Linux下的包管理器,如yum/apt等,可以很方便的将之前打包好的yaml文件部署到kubernetes上。

Helm3个重要概念:

  1. Helm:一个命令行客户端工具,主要用于Kubernetes应用chart的创建、打包、发布、管理。
  2. Chart:应用描述,一系列用于描述ks资源相关文件的集合。可以理解为yaml的集合。
  3. Release:基于Chart的部署实体,一个chart被Helm运行后将会生成对应的一个release;将在k8s中创建出真实运行的资源对象。可实现应用级别的版本管理。

Helm v3 (2019) 版本变化:架构变化

  • 删除Tiller (此前版本通过Tiller操作集群)
  • release可以在不同的命名空间重用
  • 将chart推送到docker仓库中

confluence容器化部署 kubernetes如何简化容器化部署_容器_79

5.7.3 安装和配置仓库

① helm安装
  1. 下载 Helm 压缩文件,上传到Linux系统中。
  2. 解压helmy压缩文件,将解压后的helm目录复制到/usr/bin目录下。

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_80

② 配置helm仓库
  1. 添加仓库 helm repo add [repo_name] [repo_address]
helm repo add stable http://mirror.azune.cn/kubernetes/charts/
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
helm repo update
  1. 查看仓库 helm repo list
  2. 更新仓库地址 helm repo update
  3. 删除仓库 helm repo remove [repo_name]

5.7.4 快速部署应用

  1. 使用命令搜索应用: helm search repo [key_word]
  2. 根据搜索内容选择安装:helm install [name] [app_name]

查看安装后状态:helm listhelm status [name]

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_81


使其可从外部访问:修改Service的yaml文件,type改为NodePort(kubectl edit svc ui-weave-scope

confluence容器化部署 kubernetes如何简化容器化部署_k8s_82

confluence容器化部署 kubernetes如何简化容器化部署_k8s_83

confluence容器化部署 kubernetes如何简化容器化部署_容器_84

5.7.5 自定义chart部署

自定义Chart完成部署:

  • 使用命令创建chart:helm create chart [chart_name]

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_85

  • Chart.yaml:当前chart属性配置信息
  • templates:编写yaml文件放到这个目录
  • values.yaml:yaml文件可以使用全局变量
  • 在templates文件夹创建两个yaml文件
  • deployment.yaml(kubectl create deployment web1 --image=nginx --dry-run -o yaml > deployment.yaml
  • service.yaml(先创建再删除/根据模板修改:kubectl expose deployment web1 --port=80 --target-port=80 --type=NodePort --dry-run -o yaml > service.yaml
  • 安装mychart
  • 应用升级:helm upgrade [chart_name] [chart_dir]

5.7.6 chart模板使用

实现yaml高效复用:

  • 通过传递参数,动态渲染模板,yaml内容动态传入参数生成
  • 在 chart 有 values.yaml 文件,定义 yaml 文件全局变量
  • yaml文件大体上有这些地方不同
  • image
  • tag
  • label
  • port
  • replicas

  • 在values.yaml定义变量和值

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_86

  • 在具体yaml文件,获取使用定义变量值(格式:{{ .Values.[var_name]}};动态生成名称:{{ .Release.Name}}
  • deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name}}-dep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: {{ .Values.label}}
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: {{ .Values.label}}
    spec:
      containers:
      - image: {{ .Values.image}}
        name: nginx
        resources: {}
status: {}
  • service.yaml:
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name}}-svc
spec:
  ports:
  - port: {{ .Values.port}}
    protocol: TCP
    targetPort: 80
  selector:
    app: {{ .Values.label}}
  type: NodePort
status:
  loadBalancer: {}

使用helm install --dry-run web2 mychart/命令查看生成yaml,验证结果,直接安装也可验证:

confluence容器化部署 kubernetes如何简化容器化部署_confluence容器化部署_87

5.8 持久化存储

5.8.1 nfs网络存储

数据卷 empty dir,为本地存储。pod重启后,数据不存在,需对数据持久化存储。

nfs 网络存储

pod重启数据,仍存在。


  1. 找一台服务器作为nfs服务端,安装nfs(yum install -y nfs-utils
  2. nfs服务端设置挂载路径:
vim /etc/exports
# 写入信息:
 *(rw,no_root_squash)
  1. nfs服务端创建挂载路径:
mkdir /data/nfs
  1. 在k8s集群node节点安装nfs(yum install -y nfs-utils
  2. 在nfs服务端启动nfs服务
  3. 在ks集群部署应用使用nfs网络持久存储
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dep1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: wwwroot
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes: 
      - name: wwwroot
        nfs:
          server: 192.168.1.139	# nfs server ip
          path: /data/nfs
  1. 在nfs服务器目录创建文件后,进入容器 寻找/usr/share/nginx/html目录内主页信息,查看文件是否读取。
  2. 创建Service-NodePort,在浏览器查看主页信息是否发生变化。

5.8.2 PV和PVC

PV

持久化存储,对存储资源进行抽象,对外提供一个可以调用的地方。

PVC

用于调用,不需要关心内部实现细节。


实现流程

  1. 应用部署
  2. 定义PVC(绑定PV)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dep1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: wwwroot
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes:
      - name: wwwroot
        persistentVolumeClaim:
          claimName: my-pvc

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  1. 定义PV(数据存储服务器IP、路径;定义存储容量storage、匹配模式accessModes-RW)
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /k8s/nfs
    server: 192.168.1.139

6. 集群监控平台系统

6.1 监控指标和方案

6.1.1 监控指标

  • 集群监控
  • 节点资源利用率
  • 节点数
  • 运行pods
  • Pod监控
  • 容器指标
  • 应用程序

6.1.2 监控平台搭建方案

组件: prometheus + Grafana

  • prometheus
  • 开源
  • 监控、报警
  • 内置数据库
  • 以HTTP协议周期性抓取被监控组件状态
  • 无需复杂的集成过程,使用http接口接入即可
  • Grafana:
  • 开源
  • 数据分析、可视化工具
  • 支持多种数据源

confluence容器化部署 kubernetes如何简化容器化部署_k8s_88

6.2 搭建监控平台

  • 部署守护进程 node.exporter.yaml(kubectl create -f node-exporter.yaml):
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: kube-system
  labels:
    k8s-app: node-exporter
spec:
  selector:
    matchLabels:
      k8s-app: node-exporter
  template:
    metadata:
      labels:
        k8s-app: node-exporter
    spec:
      containers:
      - image: prom/node-exporter
        name: node-exporter
        ports:
        - containerPort: 9100
          protocol: TCP
          name: http
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: node-exporter
  name: node-exporter
  namespace: kube-system
spec:
  ports:
  - name: http
    port: 9100
    nodePort: 31672
    protocol: TCP
  type: NodePort
  selector:
    k8s-app: node-exporter
  • 部署 prometheus:
  • rbac-setup.yaml(kubectl create -f rbac-setup.yaml):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: kube-system
  • configMap.yaml(kubectl create -f configMap.yaml):
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: kube-system
data:
  prometheus.yml: |
    global:
      scrape_interval:     15s
      evaluation_interval: 15s
    scrape_configs:

    - job_name: 'kubernetes-apiservers'
      kubernetes_sd_configs:
      - role: endpoints
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: default;kubernetes;https

    - job_name: 'kubernetes-nodes'
      kubernetes_sd_configs:
      - role: node
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - target_label: __address__
        replacement: kubernetes.default.svc:443
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/${1}/proxy/metrics

    - job_name: 'kubernetes-cadvisor'
      kubernetes_sd_configs:
      - role: node
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - target_label: __address__
        replacement: kubernetes.default.svc:443
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

    - job_name: 'kubernetes-service-endpoints'
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
        action: replace
        target_label: __scheme__
        regex: (https?)
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        action: replace
        target_label: kubernetes_name

    - job_name: 'kubernetes-services'
      kubernetes_sd_configs:
      - role: service
      metrics_path: /probe
      params:
        module: [http_2xx]
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
        action: keep
        regex: true
      - source_labels: [__address__]
        target_label: __param_target
      - target_label: __address__
        replacement: blackbox-exporter.example.com:9115
      - source_labels: [__param_target]
        target_label: instance
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        target_label: kubernetes_name

    - job_name: 'kubernetes-ingresses'
      kubernetes_sd_configs:
      - role: ingress
      relabel_configs:
      - source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_probe]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
        regex: (.+);(.+);(.+)
        replacement: ${1}://${2}${3}
        target_label: __param_target
      - target_label: __address__
        replacement: blackbox-exporter.example.com:9115
      - source_labels: [__param_target]
        target_label: instance
      - action: labelmap
        regex: __meta_kubernetes_ingress_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_ingress_name]
        target_label: kubernetes_name

    - job_name: 'kubernetes-pods'
      kubernetes_sd_configs:
      - role: pod
      relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: kubernetes_pod_name
  • prometheus.deploy.yaml(kubectl create -f prometheus.deploy.yaml):
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    name: prometheus-deployment
  name: prometheus
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - image: prom/prometheus:v2.0.0
        name: prometheus
        command:
        - "/bin/prometheus"
        args:
        - "--config.file=/etc/prometheus/prometheus.yml"
        - "--storage.tsdb.path=/prometheus"
        - "--storage.tsdb.retention=24h"
        ports:
        - containerPort: 9090
          protocol: TCP
        volumeMounts:
        - mountPath: "/prometheus"
          name: data
        - mountPath: "/etc/prometheus"
          name: config-volume
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
          limits:
            cpu: 500m
            memory: 2500Mi
      serviceAccountName: prometheus    
      volumes:
      - name: data
        emptyDir: {}
      - name: config-volume
        configMap:
          name: prometheus-config
  • prometheus.svc.yaml(kubectl create -f prometheus.svc.yaml):
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: prometheus
  name: prometheus
  namespace: kube-system
spec:
  type: NodePort
  ports:
  - port: 9090
    targetPort: 9090
    nodePort: 30003
  selector:
    app: prometheus

confluence容器化部署 kubernetes如何简化容器化部署_kubernetes_89

  • 部署 Grafana
  • grafana-deploy.yaml(kubectl create -f grafana-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana-core
  namespace: kube-system
  labels:
    app: grafana
    component: core
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
      component: core
  template:
    metadata:
      labels:
        app: grafana
        component: core
    spec:
      containers:
      - image: grafana/grafana:4.2.0
        name: grafana-core
        imagePullPolicy: IfNotPresent
        # env:
        resources:
          # keep request = limit to keep this container in guaranteed class
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
        env:
          # The following env variables set up basic auth twith the default admin user and admin password.
          - name: GF_AUTH_BASIC_ENABLED
            value: "true"
          - name: GF_AUTH_ANONYMOUS_ENABLED
            value: "false"
          # - name: GF_AUTH_ANONYMOUS_ORG_ROLE
          #   value: Admin
          # does not really work, because of template variables in exported dashboards:
          # - name: GF_DASHBOARDS_JSON_ENABLED
          #   value: "true"
        readinessProbe:
          httpGet:
            path: /login
            port: 3000
          # initialDelaySeconds: 30
          # timeoutSeconds: 1
        volumeMounts:
        - name: grafana-persistent-storage
          mountPath: /var
      volumes:
      - name: grafana-persistent-storage
        emptyDir: {}
  • grafana-ing.yaml(kubectl create -f grafana-ing.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: grafana
   namespace: kube-system
spec:
   rules:
   - host: k8s.grafana
     http:
       paths:
       - path: /
         backend:
          serviceName: grafana
          servicePort: 3000
  • grafana-svc.yaml(kubectl create -f grafana-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: kube-system
  labels:
    app: grafana
    component: core
spec:
  type: NodePort
  ports:
    - port: 3000
  selector:
    app: grafana
    component: core
  • 打开Grafana,配置数据源,导入显示模板。
  • 通过查看端口号访问:
  • 默认用户名和密码为admin:
  • 配置数据源,使用 Prometheus:

配置时 http://CLUSTER-IP:Port需填入:prometheus的CLUSTER-IP与Port:

confluence容器化部署 kubernetes如何简化容器化部署_容器_90


confluence容器化部署 kubernetes如何简化容器化部署_容器_91

  • 设置显示模板:
    设置

confluence容器化部署 kubernetes如何简化容器化部署_docker_92

confluence容器化部署 kubernetes如何简化容器化部署_docker_93