在部署应用程序的方式上,主要经理了三个时代:
容器化部署方式带来的问题:
容器管理的问题通常称为容器编排问题,为了解决这些容器编排问题,就产生了一些容器编排的软件。
kubernetes 是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器 Borg 系统的一个开源版本,于 2014 年 9 月发布第一个版本,2015年7月发布第一个正式版本。
kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。它的目的就是实现资源管理的自动化,主要提供了如下的主要功能:
一个 kubernetes 集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。
master:集群的控制平面,负责集群的决策。
node:集群的数据平面,负责为容器提供运行环境。
下面,以部署一个 nginx 服务来说明 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 的运行环境。
集群类型:kubernetes 集群大体上分为两类,一主多从和多主多从。
说明:为了测试简单,本次搭建的是 一主两从 类型的集群
kubernetes 有多种部署方式,目前主流的方式有
说明:现在需要安装 kubernetes 的集群环境,但是又不想过于麻烦,所以选择使用 kubeadm 方式。
作用 | IP地址 | 操作系统 | 配置 |
---|---|---|---|
Master | 192.168.3.53 | Centos7 基础设施服务器 | 2颗CPU、2G内存、50G硬盘 |
Node1 | 192.168.3.54 | Centos7 基础设施服务器 | 2颗CPU、2G内存、50G硬盘 |
Node2 | 192.168.3.55 | Centos7 基础设施服务器 | 2颗CPU、2G内存、50G硬盘 |
本次环境搭建需要安装三台 Centos 服务器 (一主二从),然后在每台服务器中分别安装 docker(18.06.3)、kubeadm(1.17.4)、kubelet(1.17.4)、kubectl(1.17.4) 程序。
# 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 系统。
# 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
# 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
# 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
下面开始对集群进行初始化,并将 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
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
接下来在 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
在 kubernetes 中,所有的内容都抽象为资源,用户需要操作资源来管理 kubernetes。
kubernetes 的本质上就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务,其实就是在 kubernetes 集群中运行一个个的容器,并将指定的程序跑在容器中。
kubernetes 的最小管理单元是 pod 而不是容器,所以只能将容器放在 Pod 中,而 kubernetes 一般也不会直接管理 Pod,而是通过 Pod 控制器来管理 Pod 的。
Pod 可以提供服务之后,就要考虑如何访问 Pod 中的服务,kubernetes 提供了 Service 资源实现这个功能。
当然,如果 Pod 中程序的数据需要持久化,kubernetes 还提供了各种存储系统。
学习 kubernetes 的核心,就是学习如何对集群上的 Pod、Pod控制器、Service、存储等各种资源进行操作。
YAML 是一个类似 XML、JSON 的标记性语言。它强调以数据为中心,并不是以标识语言为重点。因而 YAML 本身的定义比较简单,号称 “一种人性化的数据格式语言”。
YAML 的语法比较简单,主要有下面几个:
YAML 支持以下几种数据类型:
- 书写 yaml 切记 : 后面要加一个空格
- 如果需要将多段 yaml 配置放在一个文件中,中间要使用 — 分割
- yaml 转 json 的网站,可以通过它验证 yaml 是否书写正确
命令式对象管理:直接使用命令去操作 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
类型 | 操作对象 | 适用环境 | 优点 | 缺点 |
---|---|---|---|---|
命令式对象管理 | 对象 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 |
命令式对象配置 | 文件 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
声明式对象配置 | 目录 | 开发 | 支持目录操作 | 意外情况下难以调试 |
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
命令式对象配置就是使用命令配合配置文件一起来操作 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
# 1. 执行 apply 命令,用于创建或更新资源,create、patch
kubectl apply -f nginxpod.yaml
如何在 kubernetes 集群中部署一个 nginx 服务,并且能够对齐进行访问。
Namespace 是 kubernetes 系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。
Kubernetes 在集群启动之后,会默认创建几个 namespace:
下面是 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
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
Label 是 kubernetes 系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。
Label 的特点:
可以通过 Label 实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。
一些常用 Label 示例如下:
# 版本标签
version: release
# 环境标签
environment: dev
# 架构标签
tier: frontend
标签定义完毕之后,还要考虑到标签的选择,这就要使用到 Label Selector,即:
当前有两种 Label Selector:
标签的选择条件可以使用多个,此时将多个 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
在 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
利用 Deployment 可以创建一组 Pod 来提供具有高可用性的服务。
虽然每个 Pod 都会分配一个单独的 Pod 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
# 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
# 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
# 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
安装 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/
为了持久化保存容器的数据,kubernetes 引入了 Volume 的概念。
volume 是 Pod 中能够被多个容器访问的共享目录,它被定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下,kubernetes 通过 volume 实现同一个 Pod 中不同容器之间的数据共享以及数据的持久化存储。
volume 的生命周期不与 Pod 中单个容器的生命周期相关,当容器终止或重启时,volume 中的数据也不会丢失。
kubernetes 的 volume 支持多种类型,比较常见的有下面几个:
EmptyDir 是最基础的 Volume 类型,一个 EmptyDir 就是 Host 上的一个空目录。
EmptyDir 是在 Pod 被分配到 Node 时创建的,它的初始内容为空,并且无需指定宿主机上对应的目录文件,因为 kubernetes 会自动分配一个目录,当 Pod 销毁时,EmptyDir 中的数据也会被永久删除。
EmptyDir 的用途:
通过一个容器之间文件共享的案例来使用 EmptyDir :在一个 Pod 中准备两个容器 nginx 和 busybox, 然后声明一个 volume 分别挂载到两个容器的目录中,然后 nginx 容器负责向 volume 中写日志,容器 busybox 中通过命令将日志读到控制台。
创建 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
如果想简单的将数据持久化到主机中,可以选择 HostPath。
HostPath 就是将 node 主机中一个实际目录挂载到 Pod 中,以供容器使用,这样的设计就可以保证 Pod 销毁了,但是数据依旧可以存在于 Node 主机上。
创建一个 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
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
为了能够屏蔽底层存储实现的细节,方便用户使用,kubernetes 引入了 PV 和 PVC 两种资源对象。
使用了 PV 和 PVC 之后,工作可以得到进一步的细分:
实验:使用 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
实验:创建 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
PVC 和 PV 是一一对应的,PV 和 PVC 之间的相互作用遵循以下生命周期。
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
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
kubernetes 作为一个 分布式集群的管理工具,保证集群的安全性是其一个重要的任务。所谓安全性其实就是保证对 kubernetes 的各种客户端进行认证和鉴权操作。
在 kubernetes 集群中,客户端通常有两类:
认证、授权、准入机制:ApiServer 是访问及管理资源对象的唯一入口,任何一个请求访问 ApiServer, 都要经过下面的三个流程:
kubernetes 集群安全的最关键点在于如何识别并认证客户端身份,它提供了3种客户端身份认证方式:
Https 认证流程
API Server 目前支持以下几种策略:
RBAC 引入了 4 个顶级资源对象:
实验:创建一个只能管理 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
通过认证和授权之后,还需要经过准入控制处理通过后,api server 才会处理这个请求。
准入控制是一个可配置的控制器列表,可以在 Api-Server 上通过命令行设置选择执行哪些准入控制器
--admission-control=NamespaceLifecycle,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
kubernetes 开发了一个基于 web 的用户界面(DashBoard), 用户可以使用 DashBoard 部署容器化的应用,还可以监控应用的状态,执行故障排查以及管理 kubernetes 中各种资源。
下载 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
火狐浏览器访问成功
# 查看 配置项
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
# 停止全部容器,并且删除全部容器
docker stop $(docker ps -q) & docker rm $(docker ps -aq)
# 删除全部镜像
docker rmi $(docker images -q)