kubernetes之1---yum部署K8S集群

k8s集群yum安装

目录

k8s集群架构

核心组件:

1563068809299


Add-ons:

组件名称 说明
kube-dns 负责为整个集群提供DNS服务
Ingress Controller 为服务提供外网入口
Heapster 提供资源监控
Dashboard 提供GUI
Federation 提供跨可用区的集群
Fluentd-elasticsearch 提供集群日志采集、存储与查询

环境准备

主机名 IP 配置
k8s-master 10.0.0.11 1核1G
k8s-node-1 10.0.0.12 1核1G
k8s-node-2 10.0.0.13 1核1G
  • 关闭:selinuxfirewalldNetworkManagerpostfix(非必须)

  • 修改IP地址、主机名

hostnamectl set-hostname 主机名
sed -i 's/200/IP/g' /etc/sysconfig/network-scripts/ifcfg-eth0
  • 添加hosts解析
cat >> /etc/hosts <<EOF
10.0.0.11 k8s-master
10.0.0.12 k8s-node-1
10.0.0.13 k8s-node-2
10.0.0.14 k8s-node-3
EOF

master部署

etcd

  1. 安装
yum install etcd -y
  1. 配置
sed -i "6c ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"" /etc/etcd/etcd.conf
sed -i "21c ETCD_ADVERTISE_CLIENT_URLS=\"http://10.0.0.11:2379\"" /etc/etcd/etcd.conf
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" # 数据文件存放路径
#ETCD_WAL_DIR=""
#ETCD_LISTEN_PEER_URLS="http://localhost:2380" # 同类监听地址,用于集群时同步
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379" # 客户端监听地址
#ETCD_MAX_SNAPSHOTS="5"  # 快照最大数量
#ETCD_MAX_WALS="5"
ETCD_NAME="default"      # 服务名,集群时不能一样
... ...
#
#[Clustering]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
... ...
  1. 启动并加入开机启动
systemctl start etcd.service
systemctl enable etcd.service
  1. 检查集群健康状态
etcdctl -C http://10.0.0.11:2379 cluster-health

要加入已有集群,先在集群再添加成员,再在成员节点修改配置文件status="existing",启动服务。

etcdctl member list
etcdctl member remove 成员
etcdctl member add nodeN URL
  1. etcdctl命令介绍
etcdctl [global options] command [command options] [arguments...]

etcdctl mk [command options] <key> <value>
etcdctl ls [command options] [key]
etcdctl set [command options] <key> <value>
etcdctl get [command options] <key>

backup          # 备份etcd目录
cluster-health  # 检查etcd群集的运行状况
mk              # 生成一个具有给定值的新键
mkdir           # 创建新目录
rm              # 删除键或目录
rmdir           # 删除键。如果是空目录或键值对
get             # 检索键的值
ls              # 检索目录
set             # 设置键的值
setdir          # 创建新目录或更新现有目录TTL
update          # 使用给定值更新现有密钥
updatedir       # 更新现有目录
watch           # 观察键的变化
exec-watch      # 观察一个键的变化并执行一个可执行文件
member          # 成员add、remove和list子命令
user            # 用户add、grant和revoke子命令
role            # 角色add、grant和revoke子命令
auth            # 总体身份验证控制

kubernetes-master

  1. 安装
yum install kubernetes-master -y
  1. 配置apiserver
sed -i "8c KUBE_API_ADDRESS=\"--insecure-bind-address=0.0.0.0\"" /etc/kubernetes/apiserver
sed -i "11c KUBE_API_PORT=\"--port=8080\"" /etc/kubernetes/apiserver
sed -i "14c KUBELET_PORT=\"--kubelet-port=10250\"" /etc/kubernetes/apiserver
sed -i "17c KUBE_ETCD_SERVERS=\"--etcd-servers=http://10.0.0.11:2379\"" /etc/kubernetes/apiserver
sed -i "s/ServiceAccount,//" /etc/kubernetes/apiserver

默认配置文件:

###
# kubernetes system config
#
# The following values are used to configure the kube-apiserver
#

# The address on the local server to listen to.
KUBE_API_ADDRESS="--insecure-bind-address=127.0.0.1"

# The port on the local server to listen on.
# KUBE_API_PORT="--port=8080"

# Port minions listen on
# KUBELET_PORT="--kubelet-port=10250"

# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379"

# Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"

# default admission control policies
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

# Add your own!
KUBE_API_ARGS=""
  1. 配置config
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.11:8080\"" /etc/kubernetes/config

默认配置文件:

###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=false"

# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://127.0.0.1:8080"
  1. 启动并加入开机启动
systemctl enable kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl start kube-apiserver.service
systemctl start kube-controller-manager.service
systemctl start kube-scheduler.service
  1. 检查服务是否安装正常
[root@k8s-master ~]# kubectl get componentstatus
NAME                 STATUS    MESSAGE             ERROR
etcd-0               Healthy   {"health":"true"}   
scheduler            Healthy   ok                  
controller-manager   Healthy   ok

node部署

kubernetes-node(集成cadvisor)

  1. 安装
yum install kubernetes-node -y
  1. 配置config
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.11:8080\"" /etc/kubernetes/config
  1. 配置kubelet
sed -i "5c KUBELET_ADDRESS=\"--address=0.0.0.0\"" /etc/kubernetes/kubelet
sed -i "8c KUBELET_PORT=\"--port=10250\"" /etc/kubernetes/kubelet
sed -i "14c KUBELET_API_SERVER=\"--api-servers=http://10.0.0.11:8080\"" /etc/kubernetes/kubelet

k8s-node-1:10.0.0.12

sed -i "11c KUBELET_HOSTNAME=\"--hostname-override=10.0.0.12\"" /etc/kubernetes/kubelet

k8s-node-2:10.0.0.13

sed -i "11c KUBELET_HOSTNAME=\"--hostname-override=10.0.0.13\"" /etc/kubernetes/kubelet

默认配置文件:

###
# kubernetes kubelet (minion) config

# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)
KUBELET_ADDRESS="--address=127.0.0.1"

# The port for the info server to serve on
# KUBELET_PORT="--port=10250"

# You may leave this blank to use the actual hostname
KUBELET_HOSTNAME="--hostname-override=127.0.0.1"

# location of the api-server
KUBELET_API_SERVER="--api-servers=http://127.0.0.1:8080"

# pod infrastructure container
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrast
ructure:latest"

# Add your own!
KUBELET_ARGS=""
  1. 启动并加入开机启动
systemctl enable docker
systemctl enable kubelet.service
systemctl enable kube-proxy.service
systemctl start kubelet.service
systemctl start kube-proxy.service
  1. 在master节点检查
kubectl get nodes
  1. 访问cadvisor的web界面:

所有节点配置flannel网络

  1. 安装
yum install flannel -y
  1. 配置
sed -i 's#127.0.0.1#10.0.0.11#g' /etc/sysconfig/flanneld
  1. master节点创建key,安装docker启动并加入开机启动
etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16","Backend": {"Type": "vxlan"} }'

flannel三种模式:

  • udp:性能最差
  • vxlan:性能较好
  • host-gw:性能最好,但云主机不能用
yum install docker -y
systemctl enable docker
systemctl start docker
  1. 启动并加入开机启动
systemctl enable flanneld.service
systemctl start flanneld.service

docker指定bip设置docker0网卡的IP

  1. 配置docker服务启动文件:启动时设置iptables规则允许转发
sed -i "/ExecStart=/i ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT" /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl restart docker
  1. 查看flannel网卡
ifconfig flannel0
  1. 验证各节点互通
docker run -it alpine
ifconfig
  1. 配置仓库信任和加速
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries": ["10.0.0.11:5000"]
}
EOF
systemctl restart docker

master部署镜像仓库

docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry

node提交镜像测试

docker tag alpine:3.9 10.0.0.11:5000/alpine:3.9
docker push 10.0.0.11:5000/alpine:3.9

查看仓库镜像文件

ls /opt/myregistry/docker/registry/v2/repositories

k8s介绍

k8s是一个docker集群的管理工具,是容器的编排工具。

Kubernetes 是用于自动部署,扩展和管理容器化应用程序的开源系统。

Kubernetes 源自Google 15 年生产环境的运维经验(使用golang重构borg(容器管理平台) -->kubernetes),同时凝聚了社区的最佳创意和实践。

Kubernetes官方文档 中文社区

k8s历史:

  • 2014年 docker容器编排工具,立项

  • 2015年7月 发布kubernetes 1.0,加入cncf基金会,孵化

  • 2016年 kubernetes 1.2干掉两个对手,docker swarm,mesos marathon

  • 2017年 1.5-1.9

  • 2018年 k8s 从cncf基金会毕业,1.10 1.11 1.12

  • 2019年:1.13,1.14,1.15,1.16,1.17

  • 2020年:1.18,1.19,1.20

cncf:Cloud Native Compute Foundation 孵化器

kubernetes (k8s):希腊语 舵手,领航者 容器编排领域,


k8s核心功能

自我修复: 重新启动失败的容器,在节点不可用时,替换和重新调度节点上的容器,对用户定义的健康检查不响应的容器会被中止,并且在容器准备好服务之前不会把其向客户端广播。

弹性伸缩: 通过监控容器的cpu的负载值,如果这个平均高于80%,增加容器的数量;如果这个平均低于10%,减少容器的数量。

服务的自动发现和负载均衡:不需要修改您的应用程序来使用不熟悉的服务发现机制,Kubernetes 为容器提供了自己的 IP 地址和一组容器的单个 DNS 名称,并可以在它们之间进行负载均衡。

滚动升级和一键回滚: Kubernetes 逐渐部署对应用程序或其配置的更改,同时监视应用程序运行状况,以确保它不会同时终止所有实例。 如果出现问题,Kubernetes会为您恢复更改,利用日益增长的部署解决方案的生态系统。

私密配置文件管理:web容器里,数据库的账户密码(测试库密码)


k8s安装方式

  • yum安装:1.5.2;最容易安装成功,最适合学习的

  • 源码编译安装:难度最大,可以安装最新版

  • 二进制安装:步骤繁琐,可以安装最新版,自动化脚本(shell,ansible,saltstack),适合生产

  • kubeadm:安装最容易,可以安装最新版,国外网络,适合生产

  • minikube:适合开发人员体验k8s, 国外网络


k8s应用场景

k8s最适合跑微服务项目!


k8s开机检查

kubectl get componentstatus
kubectl get nodes
kubectl get pod -o wide
[root@k8s-master ~]# kubectl get componentstatus # 检查组件状态
NAME                 STATUS    MESSAGE             ERROR
etcd-0               Healthy   {"health":"true"}   
scheduler            Healthy   ok                  
controller-manager   Healthy   ok                  
[root@k8s-master ~]# kubectl get nodes # 检查nodes节点状态
NAME        STATUS    AGE
10.0.0.12   Ready     21m
10.0.0.13   Ready     3d
[root@k8s-master ~]# kubectl get pod -o wide # 检查pod节点状态
NAME          READY     STATUS    RESTARTS   AGE       IP             NODE
nginx-8phch   1/1       Running   1          13h       172.18.100.2   10.0.0.13
nginx-dc8wc   1/1       Running   1          13h       172.18.100.3   10.0.0.13
nginx-kcmpv   1/1       Running   1          13h       172.18.100.4   10.0.0.13
nginx-mknrb   1/1       Running   1          13h       172.18.100.6   10.0.0.13
nginx-zk9kg   1/1       Running   0          8s        172.18.68.2    10.0.0.12
[root@k8s-master ~]# ping 172.18.100.2
PING 172.18.100.2 (172.18.100.2) 56(84) bytes of data.
64 bytes from 172.18.100.2: icmp_seq=1 ttl=63 time=3.82 ms
64 bytes from 172.18.100.2: icmp_seq=2 ttl=63 time=0.380 ms
^C
--- 172.18.100.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.380/2.104/3.829/1.725 ms
[root@k8s-master ~]# ping 172.18.68.2
PING 172.18.68.2 (172.18.68.2) 56(84) bytes of data.
64 bytes from 172.18.68.2: icmp_seq=1 ttl=63 time=2.48 ms
64 bytes from 172.18.68.2: icmp_seq=2 ttl=63 time=0.354 ms
^C
--- 172.18.68.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.354/1.421/2.488/1.067 ms

k8s资源

准备:

node下载镜像,上传至私有仓库

docker pull nginx:1.13
docker tag docker.io/nginx:1.13 10.0.0.11:5000/nginx:1.13
docker push 10.0.0.11:5000/nginx:1.13
docker pull nginx:1.15
docker tag docker.io/nginx:1.15 10.0.0.11:5000/nginx:1.15
docker push 10.0.0.11:5000/nginx:1.15
docker pull alpine
docker tag docker.io/alpine:latest 10.0.0.11:5000/alpine:latest
docker push 10.0.0.11:5000/alpine:latest

Pod

Pod(容器组)是 Kubernetes 中最小的调度单元,可以通过 yaml 定义文件直接创建一个 Pod。

Pod 本身并不具备自我恢复(self-healing),弹性伸缩等高级特性。如果一个 Pod 所在的节点出现故障,或者调度程序自身出现问题,以及节点资源不够或节点进入维护而驱逐 Pod 时,Pod 将被删除,且不能自我恢复。

启动一个pod,至少会有两个容器,基础容器pause和业务容器,多个业务容器共享一个基础容器。一个Pod中的容器默认共享网络命名空间,

Pod容器分类

  • Infrastructure Container:基础容器pause,维护整个Pod网络空间。
  • InitContainers:初始化容器,先于业务容器开始执行。
  • Containers:业务容器,并行启动。

Pod存在的意义:为亲密性应用而存在

  • 两个应用之间发生文件交互
  • 两个应用需要通过127.0.0.1或socker通信
  • 两个应用需要发生频繁的调用

任何一个k8s资源都可以由yml清单文件来定义。

apiVersion: v1       # 版本号
kind: Pod            # Pod
metadata:            # 元数据
  name: string       # Pod名称
  namespace: string  # Pod所属的命名空间
  labels:            # 自定义标签
    - name: string   # 自定义标签名字
  annotations:       # 自定义注释列表
    - name: string
spec:                # Pod中容器的详细定义
  containers:        # Pod中容器列表
  - name: string     # 容器名称
    image: string    # 容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] # 获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]  # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     # 容器的启动命令参数列表
    workingDir: string # 容器的工作目录
    volumeMounts:      # 挂载到容器内部的存储卷配置
    - name: string     # 引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    # 存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    # 是否为只读模式
    ports:             # 需要暴露的端口库号列表
    - name: string     # 端口号名称
      containerPort: int   # 容器需要监听的端口号
      hostPort: int    # 容器所在主机需要监听的端口号,默认与Container相同
      protocol: string # 端口协议,支持TCP和UDP,默认TCP
    env:               # 容器运行前需设置的环境变量列表
    - name: string     # 环境变量名称
      value: string    # 环境变量的值
    resources:         # 资源限制和请求的设置
      limits:          # 资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:        # 资源请求的设置
        cpu: string    # Cpu请求,容器启动的初始可用数量
        memory: string # 内存请求,容器启动的初始可用数量
    livenessProbe:     # 对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:          # 对Pod容器内检查方式设置为exec方式
        command: [string]  # exec方式需要制定的命令或脚本
      httpGet:       # 对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     # 对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  # 容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure] # Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  # 设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:      # Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork:false      # 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:           # 在该pod上定义共享存储卷列表
    - name: string     # 共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     # 类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string   # Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:          # 类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:      # 类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

k8s yaml的主要组成:

  • apiVersion:v1 :api版本
  • kind:pod :资源类型
  • metadata :属性
  • spec :详细

  1. master节点编写pod资源yaml
mkdir -p /root/k8s_yaml/pod && cd /root/k8s_yaml/pod
cat > /root/k8s_yaml/pod/k8s_pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: web
spec:
  containers:
    - name: nginx
      image: 10.0.0.11:5000/nginx:1.13
      ports:
        - containerPort: 80
EOF
  1. master节点创建资源
kubectl create -f k8s_pod.yaml
  1. master节点查看所有pod资源状态(集装箱化)
[root@k8s-master pod]# kubectl get pod
NAME      READY     STATUS              RESTARTS   AGE
nginx     0/1       ContainerCreating   0          27m
  1. master节点查看指定pod资源描述(调度至10.0.0.13)
[root@k8s-master pod]# kubectl describe pod nginx
Name:		nginx
Namespace:	default
Node:		10.0.0.13/10.0.0.13
Start Time:	Mon, 07 Dec 2020 16:19:46 +0800
Labels:		app=web
Status:		Pending
IP:		
Controllers:	<none>
Containers:
  nginx:
    Container ID:		
    Image:			10.0.0.11:5000/nginx:1.13
    Image ID:			
    Port:			80/TCP
    State:			Waiting
      Reason:			ContainerCreating
    Ready:			False
    Restart Count:		0
    Volume Mounts:		<none>
    Environment Variables:	<none>
Conditions:
  Type		Status
  Initialized 	True 
  Ready 	False 
  PodScheduled 	True 
No volumes.
QoS Class:	BestEffort
Tolerations:	<none>
Events:
  FirstSeen	LastSeen	Count	From			SubObjectPath	Type		Reason		Message
  ---------	--------	-----	----			-------------	--------	------		-------
  27m		27m		1	{default-scheduler }			Normal		Scheduled	Successfully assigned nginx to 10.0.0.13
  27m		1m		10	{kubelet 10.0.0.13}			Warning		FailedSync	Error syncing pod, skipping: failed to "StartContainer" for "POD" with ErrImagePull: "image pull failed for registry.access.redhat.com/rhel7/pod-infrastructure:latest, this may be because there are no credentials on this request.  details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"

  27m	39s	116	{kubelet 10.0.0.13}		Warning	FailedSync	Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: "Back-off pulling image \"registry.access.redhat.com/rhel7/pod-infrastructure:latest\""

  0s	0s	1	{kubelet 10.0.0.13}		Warning	MissingClusterDNS	kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
  1. node节点(10.0.0.13)搜索缺失镜像并下载,上传至私有仓库
docker search pod-infrastructure
docker pull docker.io/tianyebj/pod-infrastructure
docker tag docker.io/tianyebj/pod-infrastructure:latest 10.0.0.11:5000/pod-infrastructure:latest
docker push 10.0.0.11:5000/pod-infrastructure:latest
  1. 所有node节点修改配置文件,指定POD下载镜像地址为私有仓库,重启服务
sed -i "17c KUBELET_POD_INFRA_CONTAINER=\"--pod-infra-container-image=10.0.0.11:5000/pod-infrastructure:latest\"" /etc/kubernetes/kubelet
systemctl restart kubelet.service
  1. master节点再次查看所有pod资源状态(运行中)
[root@k8s-master pod]# kubectl get pod -o wide  # -o 显示更宽
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
nginx     1/1       Running   0          59m       172.18.100.2   10.0.0.13
  1. node节点(10.0.0.13)查看运行的容器
[root@k8s-node-2 ~]# docker ps
CONTAINER ID        IMAGE                                      COMMAND                  CREATED             STATUS              PORTS               NAMES
f4a6497de298        10.0.0.11:5000/nginx:1.13                  "nginx -g 'daemon ..."   34 minutes ago      Up 34 minutes                           k8s_nginx.91390390_nginx_default_f70dd446-3864-11eb-b602-000c295a6f81_362db3ed
8cf407292934        10.0.0.11:5000/pod-infrastructure:latest   "/pod"                   34 minutes ago      Up 34 minutes                           k8s_POD.177f01b0_nginx_default_f70dd446-3864-11eb-b602-000c295a6f81_9d56b0b4
[root@k8s-node-2 ~]# docker inspect f4a6497de298 | grep NetworkMode
            "NetworkMode": "container:8cf407292934095b3ddabecb197adb33acda43bc38a7ee73a12a681ca30a9a43",
[root@k8s-node-2 ~]# docker inspect 8cf407292934 | grep -A 1 Networks
            "Networks": {
                "bridge": {

pod资源至少由两个容器组成:基础容器pause和(多个)业务容器nginx组成,共用网络空间。

基础容器pod用于实现k8s高级功能。

  1. master节点编写pod资源yaml(两个业务容器)
cat > /root/k8s_yaml/pod/k8s_pod2.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: test
  labels:
    app: web
spec:
  containers:
    - name: nginx
      image: 10.0.0.11:5000/nginx:1.13
      ports:
        - containerPort: 80
    - name: alpine
      image: 10.0.0.11:5000/alpine:latest
      command: ["sleep","1000"]
EOF
  1. master节点创建资源
kubectl create -f k8s_pod2.yaml
  1. master节点查看所有pod资源状态
[root@k8s-master pod]# kubectl get pod
NAME      READY     STATUS    RESTARTS   AGE
nginx     1/1       Running   0          2h
test      2/2       Running   1          28m
  1. node节点(10.0.0.12)查看运行的容器(轮询负载均衡)
[root@k8s-node-1 ~]# docker ps
CONTAINER ID        IMAGE                                      COMMAND                  CREATED             STATUS              PORTS               NAMES
7bf33f049a9c        10.0.0.11:5000/alpine:latest               "sleep 1000"             11 minutes ago      Up 11 minutes                           k8s_alpine.314fe414_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_48c71571
363f874e9d5a        10.0.0.11:5000/nginx:1.13                  "nginx -g 'daemon ..."   28 minutes ago      Up 28 minutes                           k8s_nginx.91390390_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_f036679b
d75cc74ef792        10.0.0.11:5000/pod-infrastructure:latest   "/pod"                   28 minutes ago      Up 28 minutes                           k8s_POD.177f01b0_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_96282638
[root@k8s-node-1 ~]# docker inspect 7bf33f049a9c | grep NetworkMode
            "NetworkMode": "container:d75cc74ef79284342d2c31698867a660c404f90a72170729b1f6728514efb84e",
[root@k8s-node-1 ~]# docker inspect 363f874e9d5a | grep NetworkMode
            "NetworkMode": "container:d75cc74ef79284342d2c31698867a660c404f90a72170729b1f6728514efb84e",
[root@k8s-node-1 ~]# docker inspect d75cc74ef792 | grep -A 1 Networks
            "Networks": {
                "bridge": {

ReplicationController

Replication Controller 副本控制器,应用托管在Kubernetes后,Kubernetes需要保证应用能够持续运行,这是RC的工作内容,它会确保任何时间Kubernetes中都有指定数量的Pod正在运行。在此基础上,RC还提供了一些高级的特性,比如滚动升级、升级回滚等。

新版 Kubernetes 建议使用 ReplicaSet(简称为RS )来取代 ReplicationController。


  1. master节点编写ReplicationController资源yaml
mkdir -p /root/k8s_yaml/rc && cd /root/k8s_yaml/rc
cat > /root/k8s_yaml/rc/k8s_rc.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 5  # 副本5个
  selector:
    app: myweb
  template:    # Pod模板
    metadata:
      labels:
        app: myweb
    spec:
      containers:
      - name: myweb
        image: 10.0.0.11:5000/nginx:1.13
        ports:
        - containerPort: 80
EOF
  1. master节点创建资源(5个pod)
kubectl create -f k8s_rc.yaml
  1. master节点查看资源状态
[root@k8s-master rc]# kubectl get rc
NAME      DESIRED   CURRENT   READY     AGE
nginx     5         5         5         6s
[root@k8s-master rc]# kubectl get pod
NAME          READY     STATUS    RESTARTS   AGE
nginx         1/1       Running   0          2h
nginx-2w6fb   1/1       Running   0          1m
nginx-35m8t   1/1       Running   0          1m
nginx-7xhms   1/1       Running   0          1m
nginx-kxljm   1/1       Running   0          1m
nginx-sv4d5   1/1       Running   0          1m
test          2/2       Running   2          38m

rc保证指定数量的pod始终存活

  1. master节点删除一个pod,再查看资源状态:仍然有5个pod
[root@k8s-master rc]# kubectl delete pod nginx-2w6fb
pod "nginx-2w6fb" deleted
[root@k8s-master rc]# kubectl get pod
NAME          READY     STATUS    RESTARTS   AGE
nginx         1/1       Running   0          2h
nginx-35m8t   1/1       Running   0          2m
nginx-5mbbq   1/1       Running   0          4s
nginx-7xhms   1/1       Running   0          2m
nginx-kxljm   1/1       Running   0          2m
nginx-sv4d5   1/1       Running   0          2m
test          2/2       Running   2          38m
[root@k8s-master rc]# kubectl get pod -o wide
NAME          READY  STATUS    RESTARTS   AGE   IP             NODE
nginx         1/1    Running   0          2h    172.18.100.2   10.0.0.13
nginx-35m8t   1/1    Running   0          6m    172.18.100.3   10.0.0.13
nginx-5mbbq   1/1    Running   0          4m    172.18.68.5    10.0.0.12
nginx-7xhms   1/1    Running   0          6m    172.18.100.4   10.0.0.13
nginx-kxljm   1/1    Running   0          6m    172.18.68.3    10.0.0.12
nginx-sv4d5   1/1    Running   0          6m    172.18.100.5   10.0.0.13
test          2/2    Running   2          43m   172.18.68.2    10.0.0.12
  1. 关闭一个node节点(10.0.0.12)(等2分钟)
systemctl stop kubelet.service
  1. master节点查看到一个node节点离线,移除该节点
[root@k8s-master rc]# kubectl get node
NAME        STATUS     AGE
10.0.0.12   NotReady   3d
10.0.0.13   Ready      3d
[root@k8s-master rc]# kubectl delete node 10.0.0.12
node "10.0.0.12" deleted
  1. master节点查看资源状态(rc资源自动迁移)
[root@k8s-master rc]# kubectl get pod -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP             NODE
nginx         1/1       Running   0          2h        172.18.100.2   10.0.0.13
nginx-35m8t   1/1       Running   0          10m       172.18.100.3   10.0.0.13
nginx-7xhms   1/1       Running   0          10m       172.18.100.4   10.0.0.13
nginx-dhcxr   1/1       Running   0          7s        172.18.100.7   10.0.0.13
nginx-jqhr9   1/1       Running   0          7s        172.18.100.6   10.0.0.13
nginx-sv4d5   1/1       Running   0          10m       172.18.100.5   10.0.0.13

rc通过标签选择器来关联pod

  1. master节点删除一个pod
kubectl delete pod nginx-35m8t

使用--all参数删除所有指定种类资源

kubectl delete pod --all
  1. master节点查看标签
[root@k8s-master rc]# kubectl get pod --show-labels
NAME          READY     STATUS    RESTARTS   AGE       LABELS
nginx         1/1       Running   0          2h        app=web
nginx-7xhms   1/1       Running   0          14m       app=myweb
nginx-ccxz2   1/1       Running   0          11s       app=myweb
nginx-dhcxr   1/1       Running   0          4m        app=myweb
nginx-jqhr9   1/1       Running   0          4m        app=myweb
nginx-sv4d5   1/1       Running   0          14m       app=myweb
[root@k8s-master rc]# kubectl get rc -o wide
NAME      DESIRED   CURRENT   READY     AGE       CONTAINER(S)   IMAGE(S)                    SELECTOR
nginx     5         5         5         13m       myweb          10.0.0.11:5000/nginx:1.13   app=myweb
  1. 修改nginx的标签为app: myweb,自动删除最年轻的pod资源,保持5个
[root@k8s-master rc]# kubectl edit pod nginx
[root@k8s-master rc]# kubectl get pod --show-labels
NAME          READY     STATUS    RESTARTS   AGE       LABELS
nginx         1/1       Running   0          2h        app=myweb
nginx-7xhms   1/1       Running   0          16m       app=myweb
nginx-dhcxr   1/1       Running   0          5m        app=myweb
nginx-jqhr9   1/1       Running   0          5m        app=myweb
nginx-sv4d5   1/1       Running   0          16m       app=myweb

rc滚动升级

  1. 根据k8s_rc2.yaml创建升级k8s_rc2.yaml,修改:
    • name
    • app
    • image

1563093237250

cat > /root/k8s_yaml/rc/k8s_rc2.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx2
spec:
  replicas: 5
  selector:
    app: myweb2
  template:
    metadata:
      labels:
        app: myweb2
    spec:
      containers:
      - name: myweb2
        image: 10.0.0.11:5000/nginx:1.15
        ports:
        - containerPort: 80
EOF
  1. 升级(5s一个)
kubectl rolling-update nginx -f k8s_rc2.yaml --update-period=5s
[root@k8s-master rc]# kubectl rolling-update nginx -f k8s_rc2.yaml --update-period=5s
Created nginx2
Scaling up nginx2 from 0 to 5, scaling down nginx from 5 to 0 (keep 5 pods available, don't exceed 6 pods)
Scaling nginx2 up to 1
Scaling nginx down to 4
Scaling nginx2 up to 2
Scaling nginx down to 3
Scaling nginx2 up to 3
Scaling nginx down to 2
Scaling nginx2 up to 4
Scaling nginx down to 1
Scaling nginx2 up to 5
Scaling nginx down to 0
Update succeeded. Deleting nginx
replicationcontroller "nginx" rolling updated to "nginx2"
[root@k8s-master rc]# kubectl get pod -o wide
NAME           READY     STATUS    RESTARTS   AGE  IP             NODE
nginx2-725jx   1/1       Running   0          35s  172.18.100.6   10.0.0.13
nginx2-fhw68   1/1       Running   0          30s  172.18.100.3   10.0.0.13
nginx2-l4b5f   1/1       Running   0          50s  172.18.100.7   10.0.0.13
nginx2-r027f   1/1       Running   0          40s  172.18.100.8   10.0.0.13
nginx2-rkc14   1/1       Running   0          25s  172.18.100.2   10.0.0.13
[root@k8s-master rc]# curl -I 172.18.100.6
HTTP/1.1 200 OK
Server: nginx/1.15.5
Date: Mon, 07 Dec 2020 11:26:46 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 02 Oct 2018 14:49:27 GMT
Connection: keep-alive
ETag: "5bb38577-264"
Accept-Ranges: bytes
  1. 回滚(1s一个)
kubectl rolling-update nginx2 -f k8s_rc.yaml --update-period=1s
[root@k8s-master rc]# kubectl rolling-update nginx2 -f k8s_rc.yaml --update-period=1s
Created nginx
Scaling up nginx from 0 to 5, scaling down nginx2 from 5 to 0 (keep 5 pods available, don't exceed 6 pods)
Scaling nginx up to 1
Scaling nginx2 down to 4
Scaling nginx up to 2
Scaling nginx2 down to 3
Scaling nginx up to 3
Scaling nginx2 down to 2
Scaling nginx up to 4
Scaling nginx2 down to 1
Scaling nginx up to 5
Scaling nginx2 down to 0
Update succeeded. Deleting nginx2
replicationcontroller "nginx2" rolling updated to "nginx"
[root@k8s-master rc]# kubectl get pod -o wide
NAME          READY     STATUS    RESTARTS   AGE IP             NODE
nginx-4r223   1/1       Running   0          16s 172.18.100.4   10.0.0.13
nginx-8phch   1/1       Running   0          13s 172.18.100.3   10.0.0.13
nginx-dc8wc   1/1       Running   0          15s 172.18.100.2   10.0.0.13
nginx-kcmpv   1/1       Running   0          11s 172.18.100.5   10.0.0.13
nginx-mknrb   1/1       Running   0          9s  172.18.100.6   10.0.0.13
[root@k8s-master rc]# curl -I 172.18.100.6
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Mon, 07 Dec 2020 11:33:03 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes

Service

service:提供服务的自动发现和负载均衡


Pod随时会被销毁和重新创建、并且每个Pod会通过调度器将其部署到不同的N个Node节点,这样会导致Pod ip地址会发生变化。所以需要通过Service去发现Pod并获取其IP地址。

K8s中三种Ip地址类型:Node ip、cluster ip、pod ip。

Pod使用RC(Replication Controller)实现高可用,会出现一些问题:

  • 只能在k8s的内部访问,客户端无法访问,因为Pod IP是私有IP地址,外界无法访问。

  • K8s中Node端口映射不可以直接映射到的Pod IP。如果一些Pod死掉了,RC就会创建一些新的Pod,新的Pod的ip地址会变化,此时做端口映射,修改规则很麻烦。

K8s使用Service资源,kube-proxy服务自动随机分配固定不变的VIP(cluster ip),VIP地址段的范围是10.254.0.0/16。Service资源帮助pod暴露端口。


Pod与Service的关系

  • 防止Pod失联,获取Pod信息(通过label-selector关联)
  • 定义一组Pod的访问策略(负载均衡 TCP/UDP 4层)
  • 支持ClusterIP,NodePort以及LoadBalancer 三种类型
  • Server的底层实现主要有iptables和IPVS二种网络模式

每个Service关联一个应用,每个Service资源自动关连一个同名endpoints资源。


Service类型

  • ClusterIP:默认,主要实现不同Pod之间互相访问,是分配在一个集群内部,可以访问的虚拟IP(vip)。
  • NodePort:在每个Node上分配一个端口作为外部访问入口
  • LoadBalancer:工作在特定的Cloud Provider上,例如Google Cloud, AWS,OpenStack

  1. master节点编写service资源yaml
mkdir -p /root/k8s_yaml/svc && cd /root/k8s_yaml/svc
cat > /root/k8s_yaml/svc/k8s_svc.yaml <<EOF
apiVersion: v1
kind: Service           # 简称svc
metadata:
  name: myweb
spec:
  type: NodePort        # 端口映射类型,默认ClusterIP类型
  #clusterIP:10.254.1.1
  ports:
    - port: 80          # clusterIP port
      nodePort: 30000   # node port 默认30000-32767
      targetPort: 80    # pod port
  selector:             # 选择器。当有多个Pod的时候,需要使用选择器选择为那些Pod做负载均衡。和RC一样,使用标签选择器。
    app: myweb
EOF
  1. master节点创建资源
kubectl create -f k8s_svc.yaml
  1. master节点查看所有svc资源状态
[root@k8s-master svc]# kubectl get svc
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   10.254.0.1     <none>        443/TCP        3d
myweb        10.254.238.3   <nodes>       80:30000/TCP   4s
[root@k8s-master svc]# kubectl describe svc
Name:			kubernetes
Namespace:		default
Labels:			component=apiserver
			provider=kubernetes
Selector:		<none>
Type:			ClusterIP
IP:			10.254.0.1
Port:			https	443/TCP
Endpoints:		10.0.0.11:6443
Session Affinity:	ClientIP
No events.


Name:			myweb
Namespace:		default
Labels:			<none>
Selector:		app=myweb
Type:			NodePort
IP:			10.254.73.4
Port:			<unset>	80/TCP
NodePort:		<unset>	30000/TCP
Endpoints:		172.18.100.2:80,172.18.100.3:80,172.18.100.4:80 + 2 more...
Session Affinity:	None
No events.
  1. master节点访问node节点端口
[root@k8s-master svc]# curl -I http://10.0.0.12:30000
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Tue, 08 Dec 2020 01:19:56 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes

[root@k8s-master svc]# curl -I http://10.0.0.13:30000
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Tue, 08 Dec 2020 01:19:56 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes

service提供负载均衡

  1. master节点调整rc副本数量
kubectl scale rc nginx --replicas=3
  1. master节点进入3个pod容器,修改容器的首页为不同页面
kubectl get pod
kubectl exec -it pod_name1 /bin/bash
echo 'web01' > /usr/share/nginx/html/index.html
exit
kubectl exec -it pod_name2 /bin/bash
echo 'web02' > /usr/share/nginx/html/index.html
exit
kubectl exec -it pod_name3 /bin/bash
echo 'web03' > /usr/share/nginx/html/index.html
exit

pod中有多个业务容器,使用参数--container进入指定业务容器

kubectl exec --container=alpine -it test /bin/sh
  1. master节点验证负载均衡
[root@k8s-master svc]# i=1;while ((i<=3));do curl http://10.0.0.12:30000;sleep 2;((i++));done
web02
web03
web01

service默认使用iptables实现四层负载均衡。

k8s 1.8版本推荐使用lvs(四层负载均衡 传输层tcp,udp)


service提供服务的自动发现

  1. master节点调整rc副本数量为2,查看pod
kubectl scale rc nginx --replicas=2
kubectl get pod
  1. master节点调整rc副本数量为3,查看pod
kubectl scale rc nginx --replicas=3
kubectl get pod

自定义nodePort范围

sed -i "26c KUBE_API_ARGS=\"--service-node-port-range=3000-50000\"" /etc/kubernetes/apiserver
systemctl restart kube-apiserver.service

命令行创建service资源(node端口只能随机)

kubectl expose rc nginx --type=NodePort --port=80 --target-port=80

service类型

第一种:NodePort类型

  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30008

第二种:ClusterIP类型,默认

  type: ClusterIP
  ports:
    - port: 80
      targetPort: 80

Deployment

rc在滚动升级之后,标签改变,但service却无法跟着改变,会造成服务访问中断,于是k8s引入了deployment资源。

Deployment 为PodReplicaSet之上,提供了一个声明式定义(declarative)方法,替代以前的ReplicationController来方便的管理应用。
只需要在Deployment中描述您想要的目标状态是什么,Deployment controller就会帮您将PodReplicaSet的实际状态改变到您的目标状态。可以定义一个新的Deployment来创建ReplicaSet或者删除已有的 Deployment并创建一个新的来替换。也就是说Deployment是可以管理多个ReplicaSet的,如下图:

img

虽然也 ReplicaSet 可以独立使用,但建议使用 Deployment 来自动管理 ReplicaSet,这样就无需担心跟其他机制的不兼容问题。


  1. master节点编写deployment资源yaml
mkdir -p /root/k8s_yaml/deploy && cd /root/k8s_yaml/deploy
cat > /root/k8s_yaml/deploy/k8s_deploy.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  strategy:              # 策略
    rollingUpdate:       # 滚动升级
      maxSurge: 1        # 多启动几个容器
      maxUnavailable: 1  # 最大不可用的pod数量
    type: RollingUpdate
  minReadySeconds: 30    # 升级间隔最小秒
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: 10.0.0.11:5000/nginx:1.13
        ports:
        - containerPort: 80
        resources:        # 资源
          limits:         # 限制
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 100m
            memory: 50Mi
EOF
  1. master节点创建资源
kubectl create -f k8s_deploy.yaml
  1. master节点查看资源状态
[root@k8s-master deploy]# kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     3         3         3            0           3s
[root@k8s-master deploy]# kubectl get pod --show-labels
NAME                     READY     STATUS    RESTARTS   AGE       LABELS
nginx-2807576163-3550z   1/1       Running   0          4s        app=nginx,pod-template-hash=2807576163
nginx-2807576163-bmxmz   1/1       Running   0          4s        app=nginx,pod-template-hash=2807576163
nginx-2807576163-pt83k   1/1       Running   0          4s        app=nginx,pod-template-hash=2807576163
nginx-8phch              1/1       Running   1          15h       app=myweb
nginx-dc8wc              1/1       Running   1          15h       app=myweb
nginx-twk24              1/1       Running   0          1h        app=myweb
[root@k8s-master deploy]# kubectl get all
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/nginx   3         3         3            3           41m

NAME       DESIRED   CURRENT   READY     AGE
rc/nginx   3         3         3         16h

NAME             CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
svc/kubernetes   10.254.0.1       <none>        443/TCP        3d
svc/myweb        10.254.73.4      <nodes>       80:30000/TCP   2h
svc/nginx        10.254.185.133   <nodes>       80:31504/TCP   38m

NAME                  DESIRED   CURRENT   READY     AGE
rs/nginx-2807576163   0         0         0         41m
rs/nginx-3014407781   3         3         3         34m

NAME                        READY     STATUS    RESTARTS   AGE
po/nginx-3014407781-4j9ld   1/1       Running   0          34m
po/nginx-3014407781-dbw3c   1/1       Running   0          30m
po/nginx-3014407781-prlzh   1/1       Running   0          34m
po/nginx-8phch              1/1       Running   1          16h
po/nginx-dc8wc              1/1       Running   1          16h
po/nginx-twk24              1/1       Running   0          2h

deployment滚动升级

deployment滚动升级不依赖配置文件,服务访问不中断;修改配置文件立即生效。

deployment升级时:更新了Pod,通过创建一个新的Replica Set(rc的升级版)并扩容3个replica,同时将原来的Replica Set缩容到0个replica。

下次更新这些pod的时候,只需要更新Deployment中的pod的template即可。

Deployment可以保证在升级时只有一定数量的Pod是down的。默认maxUnavailable: 1(最多一个不可用)。

Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod。默认maxSurge: 1(最多1个surge)。


  1. 命令行创建service资源
kubectl expose deploy nginx --type=NodePort --port=80 --target-port=80
  1. 查看service资源映射node端口
[root@k8s-master deploy]# kubectl get svc
NAME         CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   10.254.0.1       <none>        443/TCP        3d
myweb        10.254.73.4      <nodes>       80:30000/TCP   1h
nginx        10.254.185.133   <nodes>       80:31504/TCP   19s
  1. 升级:修改deployment配置文件。仅需要修改镜像版本
kubectl edit deployment nginx
  1. 访问验证:升级过程中新老版本可以同时访问
i=1;while ((i<=3));do curl -I 10.0.0.12:31504;sleep 1;((i++));done

deployment升级和回滚

命令行创建deployment(--record 记录版本变更原因)

kubectl run nginx --image=10.0.0.11:5000/nginx:1.13 --replicas=3 --record

命令行滚动升级版本

kubectl set image deployment nginx nginx=10.0.0.11:5000/nginx:1.15

pod中有多个业务容器,指定业务容器名称alpine=10.0.0.11:5000/alpine:1.15

查看deployment所有历史版本

kubectl rollout history deployment nginx

deployment回滚到上一个版本

kubectl rollout undo deployment nginx

deployment回滚到指定版本

kubectl rollout undo deployment nginx --to-revision=2

间章:练习

k8s中容器之间通过VIP相互访问

tomcat+mysql:2个deployment资源和2个service资源。tomcat访问mysql的svc提供的VIP

  1. node节点下载镜像,上传至私有仓库
docker pull tomcat-app:v2
docker tag docker.io/kubeguide/tomcat-app:v2 10.0.0.11:5000/tomcat-app:v2
docker push 10.0.0.11:5000/tomcat-app:v2
docker pull mysql:5.7
docker tag docker.io/mysql:5.7 10.0.0.11:5000/mysql:5.7
docker push 10.0.0.11:5000/mysql:5.7
  1. master节点创建配置文件
mkdir -p /root/k8s_yaml/tomcat_demo && cd /root/k8s_yaml/tomcat_demo
cat > /root/k8s_yaml/tomcat_demo/mysql-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: 10.0.0.11:5000/mysql:5.7
          ports:
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
cat > /root/k8s_yaml/tomcat_demo/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
      targetPort: 3306
  selector:
    app: mysql
EOF
cat > /root/k8s_yaml/tomcat_demo/tomcat-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 1
  selector:
    app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
        - name: myweb
          image: 10.0.0.11:5000/tomcat-app:v2
          ports:
          - containerPort: 8080
          env:
          - name: MYSQL_SERVICE_HOST
            value: 'mysql'
          - name: MYSQL_SERVICE_PORT
            value: '3306'
EOF
cat > /root/k8s_yaml/tomcat_demo/tomcat-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30008
  selector:
    app: myweb
EOF
  1. master节点创建mysql的rc和svc资源
kubectl create -f mysql-rc.yml
kubectl create -f mysql-svc.yml
  1. master节点查看所有svc资源
[root@k8s-master tomcat_demo]# kubectl get svc
NAME         CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   10.254.0.1       <none>        443/TCP        3d
mysql        10.254.37.112    <none>        3306/TCP       18s
myweb        10.254.73.4      <nodes>       80:30000/TCP   5h
nginx        10.254.185.133   <nodes>       80:31504/TCP   3h
  1. master节点删除已有同名svc资源myweb
kubectl delete svc myweb
  1. master节点修改tomcat的rc资源配置文件,修改变量MYSQL_SERVICE_HOST的值为mysql的VIP
vim tomcat-rc.yml
  1. master节点创建tomcat的rc和svc资源
kubectl create -f tomcat-rc.yml 
kubectl create -f tomcat-svc.yml
  1. 访问:http://10.0.0.12:30008/demo/

image-20201208152415164


资源创建流程

创建pod资源流程:

  • 用户和 api-server 交互,使用创建命令 kubectl create -f .
  • api-server 检查yaml文件语法
    • 错误,报错
    • 正确写入etcd数据库
  • api-server 调用 scheduler
    • 没有可用node,Pending
    • 调度成功,返回name给api-server
  • api-server调用kubelet,发送pod配置文件

删除pod资源流程:

  • 用户和 api-server 交互,使用创建命令 kubectl delete pod nginx
  • api-server 修改etcd数据库中pod的状态
  • api-server调用kubelet停止并删除容器
    • 调用失败,Unkown
  • 调用成功,api-server删除etcd数据库中pod的记录

创建deployment资源流程:

  • 用户和 api-server 交互,使用创建命令 kubectl create -f .
  • api-server 检查yaml文件语法
    • 错误,报错
    • 正确写入etcd数据库
  • controller-manager创建rs
  • controller-manager申请创建pod
  • api-server 调用 scheduler
    • 没有可用node,Pending
    • 调度成功,返回name给api-server
  • api-server调用kubelet,发送pod配置文件

DaemonSet

不需要指定副本数,有几个node节点创建几个。

在一个区域(zone)或者所有Node上运行同一个守护进程(pod)

  • 每个Node上运行一个分布式存储的守护进程,例如glusterd,ceph等。
  • 日志采集器运行在每个Node上,例如fluentd,logstash等。
  • 监控的采集端运行在每个Node,例如prometheus node exporter,collectd等。

DaemonSet的Pod调度策略与RC类似,除了使用系统内置的调度算法在每个Node上进行调度,也可以在Pod定义中使用NodeSelector或NodeAffinity来指定满足条件的Node范围进行调度。

注意:各资源labels不能一致!否则会导致pod一直删除再创建死循环。

mkdir -p /root/k8s_yaml/daemonset && cd /root/k8s_yaml/daemonset
cat > /root/k8s_yaml/daemonset/k8s_daemonset.yaml <<EOF
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx
spec:
  template:
    metadata:
      labels:
        app: oldboy
    spec:
      containers:
      - name: nginx
        image: 10.0.0.11:5000/nginx:1.13
        ports:
        - containerPort: 80
EOF
kubectl create -f k8s_daemonset.yaml
kubectl get pod -o wide

其他资源

  • StatefulSet (PetSets)
    • StatefulSet (PetSets):宠物应用,有状态的应用,pod名称固定(有序 01 02 03),适用于每个Pod中有自己的编号,需要互相访问,以及持久存储区分。例如数据库应用,redis,ES集群,mysql集群
    • 其他资源:畜生应用,无状态的应用,pod名称随机
  • Jobs
    • Jobs:一次性任务,完成状态complate
    • Pod:一直运行
  • Cronjobs:定时任务
  • Ingress
    • Ingress:七层负载均衡
    • Service:四层负载均衡
  • Secret:密码,密钥
  • ConfigMaps:配置文件

资源总结

img

k8s资源 作用
daemonSet 用来描述每个宿主机上必须且只能运行一个副本的守护进程服务
Job 用来描述一次性运行的 Pod(比如,大数据任务)
CronJob 用于描述定时任务

k8s附加组件

DNS服务

DNS服务:将svc的名称解析成对应VIP地址

  1. node2节点(10.0.0.13)下载镜像,并导入(4个镜像,来自google仓库)
[root@k8s-node-2 ~]# docker load -i docker_k8s_dns.tar.gz
8ac8bfaff55a: Loading layer 1.293 MB/1.293 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
b79219965469: Loading layer 45.91 MB/45.91 MB
Loaded image: gcr.io/google_containers/kubedns-amd64:1.9
3fc666989c1d: Loading layer 5.046 MB/5.046 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
9eed5e14d7fb: Loading layer 348.7 kB/348.7 kB
00dc4ffe8624: Loading layer  2.56 kB/2.56 kB
Loaded image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
9007f5987db3: Loading layer  5.05 MB/5.05 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
d41159f2130e: Loading layer 9.201 MB/9.201 MB
Loaded image: gcr.io/google_containers/dnsmasq-metrics-amd64:1.0
dc978cfc3e09: Loading layer 7.279 MB/7.279 MB
99740866972b: Loading layer 7.168 kB/7.168 kB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
Loaded image: gcr.io/google_containers/exechealthz-amd64:1.2
  1. master节点创建配置文件(指定调度到node2)
mkdir -p /root/k8s_yaml/dns && cd /root/k8s_yaml/dns
cat > /root/k8s_yaml/dns/skydns-svc.yaml <<EOF
# Copyright 2016 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.

# TODO - At some point, we need to rename all skydns-*.yaml.* files to kubedns-*.yaml.*

# Warning: This is a file generated from the base underscore template file: skydns-svc.yaml.base

apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "KubeDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.254.230.254
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
EOF
cat > /root/k8s_yaml/dns/skydns.yaml <<EOF
# Copyright 2016 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.

# TODO - At some point, we need to rename all skydns-*.yaml.* files to kubedns-*.yaml.*
# Should keep target in cluster/addons/dns-horizontal-autoscaler/dns-horizontal-autoscaler.yaml
# in sync with this file.

# __MACHINE_GENERATED_WARNING__

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: kube-dns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  # replicas: not specified here:
  # 1. In order to make Addon Manager do not reconcile this replicas parameter.
  # 2. Default is 1.
  # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
  strategy:
    rollingUpdate:
      maxSurge: 10%
      maxUnavailable: 0
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
        scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
    spec:
      nodeName: 10.0.0.13  # 指定调度到的node
      containers:
      - name: kubedns
        image: gcr.io/google_containers/kubedns-amd64:1.9
        resources:
          # TODO: Set memory limits when we've profiled the container for large
          # clusters, then set request = limit to keep this container in
          # guaranteed class. Currently, this container falls into the
          # "burstable" category so the kubelet doesn't backoff from restarting it.
          limits:
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi
        livenessProbe:
          httpGet:
            path: /healthz-kubedns
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /readiness
            port: 8081
            scheme: HTTP
          # we poll on pod startup for the Kubernetes master service and
          # only setup the /readiness HTTP server once that's available.
          initialDelaySeconds: 3
          timeoutSeconds: 5
        args:
        - --domain=cluster.local.
        - --dns-port=10053
        - --config-map=kube-dns
        - --kube-master-url=http://10.0.0.11:8080
        # This should be set to v=2 only after the new image (cut from 1.5) has
        # been released, otherwise we will flood the logs.
        - --v=0
        #__PILLAR__FEDERATIONS__DOMAIN__MAP__
        env:
        - name: PROMETHEUS_PORT
          value: "10055"
        ports:
        - containerPort: 10053
          name: dns-local
          protocol: UDP
        - containerPort: 10053
          name: dns-tcp-local
          protocol: TCP
        - containerPort: 10055
          name: metrics
          protocol: TCP
      - name: dnsmasq
        image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
        livenessProbe:
          httpGet:
            path: /healthz-dnsmasq
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        args:
        - --cache-size=1000
        - --no-resolv
        - --server=127.0.0.1 # 10053
        #- --log-facility=-
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        # see: https://github.com/kubernetes/kubernetes/issues/29055 for details
        resources:
          requests:
            cpu: 150m
            memory: 10Mi
      - name: dnsmasq-metrics
        image: gcr.io/google_containers/dnsmasq-metrics-amd64:1.0
        livenessProbe:
          httpGet:
            path: /metrics
            port: 10054
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        args:
        - --v=2
        - --logtostderr
        ports:
        - containerPort: 10054
          name: metrics
          protocol: TCP
        resources:
          requests:
            memory: 10Mi
      - name: healthz
        image: gcr.io/google_containers/exechealthz-amd64:1.2
        resources:
          limits:
            memory: 50Mi
          requests:
            cpu: 10m
            # Note that this container shouldn't really need 50Mi of memory. The
            # limits are set higher than expected pending investigation on #29688.
            # The extra memory was stolen from the kubedns container to keep the
            # net memory requested by the pod constant.
            memory: 50Mi
        args:
        - --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null
        - --url=/healthz-dnsmasq
        - --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1:10053 >/dev/null
        - --url=/healthz-kubedns
        - --port=8080
        - --quiet
        ports:
        - containerPort: 8080
          protocol: TCP
      dnsPolicy: Default  # Don't use cluster DNS.
EOF
  1. master节点创建DNS的资源
kubectl create -f .
  1. master节点检查命名空间kube-system
kubectl get namespace
kubectl get all -n kube-system -o wide
[root@k8s-master dns]# kubectl get all -n kube-system
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/kube-dns   1         1         1            1           10m

NAME           CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
svc/kube-dns   10.254.230.254   <none>        53/UDP,53/TCP   10m

NAME                    DESIRED   CURRENT   READY     AGE
rs/kube-dns-249145955   1         1         1         10m

NAME                          READY     STATUS    RESTARTS   AGE
po/kube-dns-249145955-wdmq8   4/4       Running   0          10m
  1. 所有node节点修改kubelet配置文件,重启服务
sed -i '20c KUBELET_ARGS=\"--cluster_dns=10.254.230.254 --cluster_domain=cluster.local\"'  /etc/kubernetes/kubelet
systemctl restart kubelet
  1. master节点修改tomcat的rc资源配置文件,修改变量MYSQL_SERVICE_HOST的值为mysql,重新创建资源
cd /root/k8s_yaml/tomcat_demo
vim tomcat-rc.yml
kubectl delete -f .
kubectl create -f .
  1. master节点验证
[root@k8s-master tomcat_demo]# kubectl get pod # 查找myweb容器名
NAME                     READY     STATUS    RESTARTS   AGE
mysql-sj480              1/1       Running   0          3m
myweb-th9rx              1/1       Running   0          1m
[root@k8s-master tomcat_demo]# kubectl exec -it myweb-th9rx /bin/bash #进入容器
root@myweb-th9rx:/usr/local/tomcat# cat /etc/resolv.conf # 查看DNS解析
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.254.230.254
nameserver 223.5.5.5
options ndots:5
root@myweb-th9rx:/usr/local/tomcat# ping mysql # 能解析,不能ping通,VIP
PING mysql.default.svc.cluster.local (10.254.106.204): 56 data bytes
^C--- mysql.default.svc.cluster.local ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
root@myweb-th9rx:/usr/local/tomcat# exit
exit

namespace命名空间

namespace:实现资源隔离

  1. 查看命名空间
kubectl get namespace
  1. 创建命名空间
kubectl create namespace tomcat
  1. 修改配置文件指定命名空间
cd /root/k8s_yaml/tomcat_demo/
sed -i "3a \ \ namespace: tomcat" *
yum install dos2unix -y
dos2unix *
  1. 删除所有svc和rc资源
kubectl delete svc --all
kubectl delete rc --all
  1. 创建rc和svc资源
kubectl create -f .
  1. 查看命名空间tomcat的所有资源
kubectl get all -n tomcat

间章:作业

k8s中容器之间通过VIP相互访问,应用DNS,namespace

wordpress+mysql:2个deployment资源和2个service资源。wordpress访问mysql的svc提供的VIP

  1. node下载镜像,上传至私有仓库
docker pull wordpress
docker tag docker.io/wordpress:latest 10.0.0.11:5000/wordpress:latest
docker push 10.0.0.11:5000/wordpress:latest
docker pull mysql:5.7
docker tag docker.io/mysql:5.7 10.0.0.11:5000/mysql:5.7
docker push 10.0.0.11:5000/mysql:5.7
  1. 创建rc和svc配置文件
mkdir -p /root/k8s_yaml/wordpress_rc && cd /root/k8s_yaml/wordpress_rc
cat > /root/k8s_yaml/wordpress_rc/mysql-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  namespace: wordpress
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.12
      containers:
        - name: mysql
          image: 10.0.0.11:5000/mysql:5.7
          ports:
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: 'root_pwd'
          - name: MYSQL_DATABASE
            value: 'blog'
          - name: MYSQL_USER
            value: 'blog'
          - name: MYSQL_PASSWORD
            value: 'blog'
          args:
          - --character-set-server=utf8
          - --collation-server=utf8_bin
EOF
cat > /root/k8s_yaml/wordpress_rc/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: wordpress
  name: mysql
spec:
  ports:
    - port: 3306
      targetPort: 3306
  selector:
    app: mysql
EOF
cat > /root/k8s_yaml/wordpress_rc/wordpress-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  namespace: wordpress
  name: wordpress
spec:
  replicas: 1
  selector:
    app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      nodeName: 10.0.0.12
      containers:
        - name: wordpress
          image: 10.0.0.11:5000/wordpress:latest
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
          env:
          - name: WORDPRESS_DB_HOST
            value: 'mysql'
          - name: WORDPRESS_DB_PASSWORD
            value: 'blog'
          - name: WORDPRESS_DB_USER
            value: 'blog'
          - name: WORDPRESS_DB_NAME
            value: 'blog'
EOF
cat > /root/k8s_yaml/wordpress_rc/wordpress-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: wordpress
  name: wordpress
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30080
  selector:
    app: wordpress
EOF

查看系统补全的配置文件

kubectl get pod NAME -n NAMESPACE -o yaml

镜像拉取策略

[root@k8s-master ~]# kubectl explain pod.spec.containers.imagePullPolicy
FIELD: imagePullPolicy <string>

DESCRIPTION:
Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
More info: http://kubernetes.io/docs/user-guide/images#updating-images
Always       每次创建Pod都会重新拉取一次镜像
Never        Pod永远不会主动拉取这个镜像
IfNotPresent 默认值,镜像在宿主机上不存在时才拉取
  1. 删除所有资源
kubectl delete svc --all
kubectl delete rc --all
kubectl delete deployment --all
  1. 创建命名空间
kubectl create namespace wordpress
  1. 创建资源
kubectl create -f .
  1. 查看svc资源,访问:http://10.0.0.12:30080/
kubectl get all -n wordpress -o wide
  1. 创建deploy和svc配置文件
mkdir -p /root/k8s_yaml/wordpress_demo && cd /root/k8s_yaml/wordpress_demo
cat > /root/k8s_yaml/wordpress_demo/mysql-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: wordpress
  name: mysql
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.12
      containers:
        - name: mysql
          image: 10.0.0.11:5000/mysql:5.7
          ports:
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: 'root_pwd'
          - name: MYSQL_DATABASE
            value: 'blog'
          - name: MYSQL_USER
            value: 'blog'
          - name: MYSQL_PASSWORD
            value: 'blog'
          args:
          - --character-set-server=utf8
          - --collation-server=utf8_bin
EOF
cat > /root/k8s_yaml/wordpress_demo/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: wordpress
  name: mysql
spec:
  ports:
    - port: 3306
      targetPort: 3306
  selector:
    app: mysql
EOF
cat > /root/k8s_yaml/wordpress_demo/wordpress-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: wordpress
  name: wordpress
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      nodeName: 10.0.0.12
      containers:
        - name: wordpress
          image: 10.0.0.11:5000/wordpress:latest
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
          env:
          - name: WORDPRESS_DB_HOST
            value: 'mysql'
          - name: WORDPRESS_DB_PASSWORD
            value: 'blog'
          - name: WORDPRESS_DB_USER
            value: 'blog'
          - name: WORDPRESS_DB_NAME
            value: 'blog'
EOF
cat > /root/k8s_yaml/wordpress_demo/wordpress-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: wordpress
  name: wordpress
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30080
  selector:
    app: wordpress
EOF

健康检查和可用性检查

探针种类:

livenessProbe:健康状态检查,周期性检查服务是否存活,检查结果失败,自动重启容器。

readinessProbe:可用性检查,周期性检查服务是否可用,不可用将从service的endpoints中移除。

探针检测方法:

  • exec:执行一段命令,返回值为0正常,非0错误。
  • httpGet:检测某个 http 请求的返回状态码 2xx,3xx正常;4xx,5xx错误。
  • tcpSocket:测试某个端口是否能够连接。

liveness探针的exec使用

mkdir -p /root/check/ && cd /root/check/
cat > /root/check/nginx_pod_exec.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: exec
spec:
  containers:
    - name: nginx
      image: 10.0.0.11:5000/nginx:1.13
      ports:
        - containerPort: 80
      args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
      livenessProbe:            # 模拟健康检查,启动后30s内健康,之后不健康
        exec:
          command:
            - cat
            - /tmp/healthy
        initialDelaySeconds: 5   # 初始化5秒后开始检查
        periodSeconds: 5         # 检查周期5s一次
        timeoutSeconds: 3        # 检查命令执行超时时间,默认1s
        successThreshold: 1      # 检查成功1次就算成功,默认1次
        failureThreshold: 1      # 检查失败1次就算失败,默认3次
EOF
kubectl create -f nginx_pod_exec.yaml
kubectl describe pod exec
mysqladmin ping  # 检测mysql存活

liveness探针的httpGet使用

cat > /root/check/nginx_pod_httpGet.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: httpget
spec:
  containers:
    - name: nginx
      image: 10.0.0.11:5000/nginx:1.13
      ports:
        - containerPort: 80
      livenessProbe:
        httpGet:
          path: /index.html
          port: 80
        initialDelaySeconds: 3
        periodSeconds: 3
EOF
kubectl create -f nginx_pod_httpGet.yaml
kubectl describe pod httpget
kubectl exec -it httpget /bin/bash
rm -f /usr/share/nginx/html/index/html
exit
kubectl describe pod httpget

liveness探针的tcpSocket使用

cat > /root/check/nginx_pod_tcpSocket.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: tcpsocket
spec:
  containers:
    - name: nginx
      image: 10.0.0.11:5000/nginx:1.13
      ports:
        - containerPort: 80
      args:
        - /bin/sh
        - -c
        - tail -f /etc/hosts
      livenessProbe:
        tcpSocket:
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 3
EOF
kubectl create -f nginx_pod_tcpSocket.yaml
kubectl describe pod tcpsocket
kubectl exec -it tcpsocket /bin/bash
nginx -s stop
exit
kubectl describe pod tcpsocket

readiness探针的httpGet使用

cat > /root/check/nginx_rc_httpGet.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: readiness
spec:
  replicas: 2
  selector:
    app: readiness
  template:
    metadata:
      labels:
        app: readiness
    spec:
      containers:
      - name: readiness
        image: 10.0.0.11:5000/nginx:1.13
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /qiangge.html
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 3
EOF
kubectl create -f nginx_rc_httpGet.yaml
kubectl expose rc readiness --type=NodePort --port=80 --target-port=80
kubectl describe svc readiness
kubectl get pod
kubectl exec -it readiness-NAME /bin/bash
echo 'web' > /usr/share/nginx/html/qiangge.html
exit
kubectl get pod
kubectl describe svc readiness

Dashboard服务

  1. node2节点(10.0.0.13)下载镜像,并导入,打标(来自tenxcloud仓库)
[root@k8s-node-2 opt]# docker load -i kubernetes-dashboard-amd64_v1.4.1.tar.gz 
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
2e350fa8cbdf: Loading layer 86.96 MB/86.96 MB
Loaded image: index.tenxcloud.com/google_containers/kubernetes-dashboard-amd64:v1.4.1
[root@k8s-node-2 opt]# docker tag index.tenxcloud.com/google_containers/kubernetes-dashboard-amd64:v1.4.1 10.0.0.11:5000/kubernetes-dashboard-amd64:v1.4.1
  1. master节点创建配置文件(指定调度到node2)
mkdir -p /root/k8s_yaml/dashboard/ && cd /root/k8s_yaml/dashboard/
cat > /root/k8s_yaml/dashboard/dashboard.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
# Keep the name in sync with image version and
# gce/coreos/kube-manifests/addons/dashboard counterparts
  name: kubernetes-dashboard-latest
  namespace: kube-system
spec:
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
        version: latest
        kubernetes.io/cluster-service: "true"
    spec:
      nodeName: 10.0.0.13  # 指定调度到的node
      containers:
      - name: kubernetes-dashboard
        image: 10.0.0.11:5000/kubernetes-dashboard-amd64:v1.4.1
        resources:
          # keep request = limit to keep this container in guaranteed class
          limits:
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 100m
            memory: 50Mi
        ports:
        - containerPort: 9090
        args:
         -  --apiserver-host=http://10.0.0.11:8080
        livenessProbe:
          httpGet:
            path: /
            port: 9090
          initialDelaySeconds: 30
          timeoutSeconds: 30
EOF
cat > /root/k8s_yaml/dashboard/dashboard-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: kubernetes-dashboard
  namespace: kube-system
  labels:
    k8s-app: kubernetes-dashboard
    kubernetes.io/cluster-service: "true"
spec:
  selector:
    k8s-app: kubernetes-dashboard
  ports:
  - port: 80
    targetPort: 9090
EOF
  1. master节点创建dashboard的资源
kubectl create -f .
  1. master节点检查命名空间kube-system
kubectl get all -n kube-system
  1. 访问http://10.0.0.11:8080/ui/

全局资源

  • Namespaces
  • Nodes
  • Persistemt Volume Claims

局部资源(各Namespaces分别使用的资源)


通过apiservice反向代理访问service资源

  1. 分析dashboard服务web页面

    主页+锚点(#)

http://10.0.0.11:8080/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard/#/workload?namespace=default
  1. 查看所有命名空间的svc
kubectl get svc --all-namespaces
  1. 通过apiservice反向代理访问service资源
http://10.0.0.11:8080/api/v1/proxy/namespaces/命名空间名称/services/service名称/

弹性伸缩

Kubernetes HPA(Horizontal Pod Autoscaler)Pod 水平自动扩缩:可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。 除了 CPU 利用率,也可以基于其他应程序提供的自定义度量指标来执行自动扩缩。 但不适用于无法扩缩的对象,比如 DaemonSet。

Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。 控制器会周期性的调整副本控制器或 Deployment 中的副本数量,以使得 Pod 的平均 CPU 利用率与用户所设定的目标值匹配。

Pod水平自动伸缩:

  • 1.11版本之前,依赖heapster监控各node节点信息。
  • 1.11版本之后,使用metric-server采集指标信息。

HPA工作机制

image-20201209163836720


安装heapster监控

k8s原生集群监控方案(Heapster+InfluxDB+Grafana+Dashboard) :

Heapster处理数据储存到InfluxDB,Grafana从InfluxDB读取数据出图,Dashboard调用Grafana的图。

image-20201209194647502

  1. node2节点(10.0.0.13)下载镜像,并导入,打标(3个镜像,来自官方仓库)
for n in `ls *.tar.gz`;do docker load -i $n ;done
docker tag docker.io/kubernetes/heapster_grafana:v2.6.0 10.0.0.11:5000/heapster_grafana:v2.6.0
docker tag  docker.io/kubernetes/heapster_influxdb:v0.5 10.0.0.11:5000/heapster_influxdb:v0.5
docker tag docker.io/kubernetes/heapster:canary 10.0.0.11:5000/heapster:canary
  1. master节点创建配置文件(指定调度到node2)
mkdir -p /root/k8s_yaml/heapster-influxdb && cd /root/k8s_yaml/heapster-influxdb
cat > /root/k8s_yaml/heapster-influxdb/heapster-controller.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    k8s-app: heapster
    name: heapster
    version: v6
  name: heapster
  namespace: kube-system
spec:
  replicas: 1
  selector:
    k8s-app: heapster
    version: v6
  template:
    metadata:
      labels:
        k8s-app: heapster
        version: v6
    spec:
      nodeName: 10.0.0.13  # 指定调度到的node
      containers:
      - name: heapster
        image: 10.0.0.11:5000/heapster:canary
        #imagePullPolicy: Always
        command:
        - /heapster
        - --source=kubernetes:http://10.0.0.11:8080?inClusterConfig=false
        - --sink=influxdb:http://monitoring-influxdb:8086
EOF
cat > /root/k8s_yaml/heapster-influxdb/influxdb-grafana-controller.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    name: influxGrafana
  name: influxdb-grafana
  namespace: kube-system
spec:
  replicas: 1
  selector:
    name: influxGrafana
  template:
    metadata:
      labels:
        name: influxGrafana
    spec:
      nodeName: 10.0.0.13  # 指定调度到的node
      containers:
      - name: influxdb
        image: 10.0.0.11:5000/heapster_influxdb:v0.5
        volumeMounts:
        - mountPath: /data
          name: influxdb-storage
      - name: grafana
        image: 10.0.0.11:5000/heapster_grafana:v2.6.0
        env:
          - name: INFLUXDB_SERVICE_URL
            value: http://monitoring-influxdb:8086
            # The following env variables are required to make Grafana accessible via
            # the kubernetes api-server proxy. On production clusters, we recommend
            # removing these env variables, setup auth for grafana, and expose the grafana
            # service using a LoadBalancer or a public IP.
          - name: GF_AUTH_BASIC_ENABLED
            value: "false"
          - name: GF_AUTH_ANONYMOUS_ENABLED
            value: "true"
          - name: GF_AUTH_ANONYMOUS_ORG_ROLE
            value: Admin
          - name: GF_SERVER_ROOT_URL
            value: /api/v1/proxy/namespaces/kube-system/services/monitoring-grafana/
        volumeMounts:
        - mountPath: /var
          name: grafana-storage
      volumes:
      - name: influxdb-storage
        emptyDir: {}
      - name: grafana-storage
        emptyDir: {}
EOF
cat > /root/k8s_yaml/heapster-influxdb/grafana-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    kubernetes.io/cluster-service: 'true'
    kubernetes.io/name: monitoring-grafana
  name: monitoring-grafana
  namespace: kube-system
spec:
  # In a production setup, we recommend accessing Grafana through an external Loadbalancer
  # or through a public IP. 
  # type: LoadBalancer
  ports:
  - port: 80
    targetPort: 3000
  selector:
    name: influxGrafana
EOF
cat > /root/k8s_yaml/heapster-influxdb/influxdb-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  labels: null
  name: monitoring-influxdb
  namespace: kube-system
spec:
  ports:
  - name: http
    port: 8083
    targetPort: 8083
  - name: api
    port: 8086
    targetPort: 8086
  selector:
    name: influxGrafana
EOF
cat > /root/k8s_yaml/heapster-influxdb/heapster-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    kubernetes.io/cluster-service: 'true'
    kubernetes.io/name: Heapster
  name: heapster
  namespace: kube-system
spec:
  ports:
  - port: 80
    targetPort: 8082
  selector:
    k8s-app: heapster
EOF
  1. master节点创建dashboard的资源
kubectl create -f .
  1. master节点检查命名空间kube-system,查看集群信息
kubectl get all -n kube-system
kubectl cluster-info
  1. 浏览器访问dashboard验证http://10.0.0.11:8080/ui/

image-20201209163459528

  1. 可以使用top命令
kubectl top node

弹性伸缩

  1. master节点创建测试Deployment和svc资源
cd /root/k8s_yaml/deploy
cat > /root/k8s_yaml/deploy/k8s_deploy2.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: 10.0.0.11:5000/nginx:1.13
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 100m
            memory: 50Mi
EOF
kubectl create -f k8s_deploy2.yaml
kubectl expose deploy nginx --type=NodePort --port=80 --target-port=80

  1. 创建弹性伸缩规则
kubectl autoscale deploy nginx --max=8 --min=1 --cpu-percent=5
  1. 查看hpa资源,nginx访问地址IP:PORT
kubectl get all -o wide
  1. 查看hpa资源配置文件
kubectl get hpa nginx -o yaml
  1. 压测
yum install httpd-tools -y
ab -n 1000000 -c 40 http://10.0.0.12:32114/index.html
  1. 验证http://10.0.0.11:8080/ui/

压测前:

image-20201209172019380

压测10s后,自动扩容

image-20201209172134559

停止压测5分钟后,自动缩容:

image-20201209172743894

持久化存储

查看解释

kubectl explain pod.spec.containers.volumeMounts
kubectl explain pod.spec.volumes

持久化存储类型:

  • emptyDir:共享pod生存期的临时目录。
  • hostPath:主机上预先存在的文件或目录直接公开给容器。这通常用于允许查看主机的系统代理或其他特权对象。
  • nfs:共享pod生存期的NFS装载。

emptyDir

临时的空目录:伴随pod的生命周期,随着pod删除而删除,数据持久化但不共享。

适用于存放日志(pod之间不同,但需要保存的数据)。

emptyDir是一种临时存储,pod创建的时候会在node节点上为容器申请一个临时的目录,跟随容器的生命周期,若容器删除,emptyDir定义的临时存储空间也会随之删除,容器发生意外crash则不受影响,同时如果容器发生了迁移,其上的数据也会丢失,emptyDir一般用于测试,或者缓存场景。注意:容器崩溃不会导致数据的丢失,因为容器的崩溃并不移除pod.

emptyDir 的一些用途:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

image-20201210135509124


  1. 创建tomcat+mysql的资源
cd /root/k8s_yaml/tomcat_demo && kubectl create -f .
  1. 访问:http://10.0.0.12:30008/demo/,添加数据
  2. node节点清空容器,虽然会重启一批容器,但之前添加的数据没了,因此需要持久化存储
docker rm -f `docker ps -aq`
  1. master节点创建emptyDir持久化配置文件
cat > /root/k8s_yaml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.12
      volumes:
      - name: mysql
        emptyDir: {}
      containers:
        - name: wp-mysql
          image: 10.0.0.11:5000/mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
  1. master节点删除原rc资源,创建emptyDir持久化的rc资源
kubectl delete -f mysql-rc.yml
kubectl create -f mysql-emptyDir.yml
  1. node节点查看临时目录
ll /var/lib/kubelet/pods/
ll /var/lib/kubelet/pods/sha256号/volumes/kubernetes.io~empty-dir/mysql

删除pod,这个文件也会自动删除。


HostPath

HostPath:可以多个容器共享持久化数据,但不能跨宿主机。

hostPath 卷能将node宿主机节点文件系统上的文件或目录挂载到您的 Pod 中。

  • 运行一个需要访问 Docker 引擎内部机制的容器;请使用 hostPath 挂载 /var/lib/docker 路径。
  • 在容器中运行 cAdvisor 时,以 hostPath 方式挂载 /sys
  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。

使用这种类型的卷时要小心,因为:

  • 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。
  • 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 hostPath 使用的资源。
  • 基础主机上创建的文件或目录只能由 root 用户写入。您需要在特权容器中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。

  1. master节点创建wordpress+mysql资源
cd /root/k8s_yaml/wordpress_demo
kubectl create namespace wordpress
kubectl create -f .
  1. master节点持久化mysql
cat > /root/k8s_yaml/wordpress_demo/mysql-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: wordpress
  name: mysql
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.12
      volumes:
      - name: mysql
        emptyDir: {}
      containers:
        - name: mysql
          image: 10.0.0.11:5000/mysql:5.7
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          ports:
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: 'root_pwd'
          - name: MYSQL_DATABASE
            value: 'blog'
          - name: MYSQL_USER
            value: 'blog'
          - name: MYSQL_PASSWORD
            value: 'blog'
          args:
          - --character-set-server=utf8
          - --collation-server=utf8_bin
EOF
  1. master节点应用配置文件:新建一个资源,此次不适用
kubectl apply -f mysql-demo.yml
kubectl get pod -o wide -n wordpress
kubectl delete deploy -n wordpress --all
kubectl create -f mysql-demo.yml
kubectl create -f wordpress-demo.yml
  1. master节点持久化wordpress
cat > /root/k8s_yaml/wordpress_demo/wordpress-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: wordpress
  name: wordpress
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      nodeName: 10.0.0.12
      volumes:
      - name: wp-code
        hostPath:
          path: /data/wp-code
      containers:
        - name: wordpress
          image: 10.0.0.11:5000/wordpress:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - name: wp-code
            mountPath: /var/www/html
          ports:
          - containerPort: 80
          env:
          - name: WORDPRESS_DB_HOST
            value: 'mysql'
          - name: WORDPRESS_DB_PASSWORD
            value: 'blog'
          - name: WORDPRESS_DB_USER
            value: 'blog'
          - name: WORDPRESS_DB_NAME
            value: 'blog'
EOF
  1. master节点替换配置文件,删除所有pod生效
mkdir -p /data/wp-code
kubectl replace -f wordpress-demo.yml
kubectl delete pod -n wordpress --all 
kubectl get pod -o wide -n wordpress
  1. 安装wordpresshttp://10.0.0.12:30080/

  2. node1(10.0.0.12)节点查看持久化目录

ll /data/wp-code
  1. wordpress上传图片

  2. node1查看上传图片

ll /data/wp-code/wp-content/uploads/

删除pod时,文件不会删除掉,还要保存到node上。

  1. master节点修改副本数
kubectl scale -n wordpress deployment wordpress --replicas=2
  1. master节点查看pod资源
kubectl get pod -o wide -n wordpress
  1. node1创建phpinfo页面
echo "<?php phpinfo() ?>" > /data/wp-code/info.php
  1. 访问phpinfo页面,验证调度到多个pod,但共享数据
curl 10.0.0.12:30080/info.php | grep -i 172.18.98

NFS

NFS:可以多个容器跨宿主机共享持久化数据。

  1. 所有节点安装nfs-utils
yum -y install nfs-utils
  1. master节点部署nfs服务
mkdir -p /data/tomcat-db
cat > /etc/exports <<EOF
/data    10.0.0.0/24(rw,sync,no_root_squash,no_all_squash)
EOF
systemctl start nfs
  1. 所有node节点检查挂载
showmount -e 10.0.0.11
  1. master节点创建nfs持久化配置文件
cd /root/k8s_yaml/tomcat_demo
cat > /root/k8s_yaml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      volumes:
      - name: mysql
        nfs:
          path: /data/tomcat-db
          server: 10.0.0.11
      containers:
        - name: wp-mysql
          image: 10.0.0.11:5000/mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
  1. master节点替换配置文件,删除所有pod生效
kubectl replace -f mysql-emptyDir.yml
kubectl delete pod --all
kubectl get pod -o wide
  1. node1查看nfs挂载
df -Th|grep nfs
  1. 访问:http://10.0.0.12:30008/demo/,添加数据

  2. master节点修改配置文件:调度到13上

cat > /root/k8s_yaml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.13
      volumes:
      - name: mysql
        nfs:
          path: /data/tomcat-db
          server: 10.0.0.11
      containers:
        - name: wp-mysql
          image: 10.0.0.11:5000/mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
  1. master节点替换配置文件,删除所有pod生效
kubectl replace -f mysql-emptyDir.yml
kubectl delete pod --all
kubectl get pod -o wide
  1. node2查看nfs挂载
df -Th|grep nfs
  1. 访问:http://10.0.0.13:30008/demo/,数据还在

PV和PVC

PersistentVolume(持久化卷):全局资源,是对底层的共享存储的一种抽象。PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。

PersistentVolumeClaim(持久化卷声明):局部资源,属于某一个namespace。PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

img

  • Volumes:最基础的存储抽象,其支持多种类型,包括本地存储、NFS、FC以及众多的云存储,我们也可以编写自己的存储插件来支持特定的存储系统。Volume可以被Pod直接使用,也可以被PV使用。普通的Volume和Pod之间是一种静态的绑定关系,在定义Pod的同时,通过volume属性来定义存储的类型,通过volumeMount来定义容器内的挂载点。
  • PersistentVolume:是Kubernetes中的一个资源对象,创建一个PV相当于创建了一个存储资源对象,这个资源的使用要通过PVC来请求。
  • PersistentVolumeClaim:是用户对存储资源PV的请求,根据PVC中指定的条件Kubernetes动态的寻找系统中的PV资源并进行绑定。目前PVC与PV匹配可以通过StorageClassName、matchLabels或者matchExpressions三种方式。
  • StorageClass:存储类,目前kubernetes支持很多存储,例如ceph,nfs。glusterfs等。

生命周期

PV是集群中的资源。PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling

img

PVC 处理流程

图片.png


Provisioning

PV的提供方式:静态或者动态。

  • Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
  • Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。

Provisioning


PV访问模式

  • RWO - ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
  • ROX - ReadOnlyMany——该卷可以被多个节点以只读模式挂载
  • RWX - ReadWriteMany——该卷可以被多个节点以读/写模式挂载

zp7dytnfgz


  1. master节点创建svc配置文件
mkdir -p /root/k8s_yaml/volume && cd /root/k8s_yaml/volume
cat > /root/k8s_yaml/volume/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: tomcat
  name: mysql
spec:
  ports:
    - port: 3306
      targetPort: 3306
  selector:
    app: mysql
EOF
cat > /root/k8s_yaml/volume/tomcat-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  namespace: tomcat
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30008
  selector:
    app: myweb
EOF
  1. master节点创建pv配置文件
mkdir -p mkdir -p /data/pv{1,2,3}
cat > /root/k8s_yaml/volume/pv1.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
  labels:
    type: nfs001
spec:
  capacity:
    storage: 10Gi                         # 不会去验证是否真的有这么多空间
  accessModes:
    - ReadWriteMany                       # 允许多个pod读写,实现共享
  persistentVolumeReclaimPolicy: Recycle  # 回收策略:回收
  nfs:
    path: "/data/pv1"
    server: 10.0.0.11
    readOnly: false
EOF
cat > /root/k8s_yaml/volume/pv2.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv2
  labels:
    type: nfs001
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: "/data/pv2"
    server: 10.0.0.11
    readOnly: false
EOF
cat > /root/k8s_yaml/volume/pv3.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv3
  labels:
    type: ssd
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: "/data/pv3"
    server: 10.0.0.11
    readOnly: false
EOF

回收策略:

kubectl explain persistentvolumes.spec.persistentVolumeReclaimPolicy
  • Retain(保留):手动回收pv。默认

  • Recycle(回收):基本擦除pv( rm -rf /thevolume/* )

  • Delete(删除):关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷) 将被删除

    当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略

  1. master节点创建pv资源
kubectl create namespace tomcat
kubectl create -f .
  1. master节点查看pv资源
kubectl get pv

pv卷状态:

  • Available(可用):一块空闲资源还没有被任何声明绑定
  • Bound(已绑定):卷已经被声明绑定
  • Released(已释放):声明被删除,但是资源还未被集群重新声明
  • Failed(失败):该卷的自动回收失败 命令行会显示绑定到 PV 的 PVC 的名称
  1. master节点创建pvc配置文件
cat > /root/k8s_yaml/volume/mysql_pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  namespace: tomcat
  name: tomcat-mysql
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 30Gi
EOF
  1. master节点创建pvc资源
kubectl create -f mysql_pvc.yaml
  1. master节点查看pv和pvc资源
kubectl get pv
kubectl get pvc -n tomcat
  1. master节点创建Deployment资源:pod模板里使用volume
cat > /root/k8s_yaml/volume/mysql-rc.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: tomcat
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeName: 10.0.0.12
      volumes:
      - name: mysql
        persistentVolumeClaim:
          claimName: tomcat-mysql
      containers:
        - name: wp-mysql
          image: 10.0.0.11:5000/mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
  1. master节点创建pvc资源
kubectl create -f mysql-rc.yml
  1. master节点验证pv和pvc资源的使用
kubectl get pv 
kubectl get pod -n tomcat
kubectl describe pod -n tomcat mysql-k90jm | grep -i persistentVolumeClaim
kubectl describe pod -n tomcat mysql-k90jm | grep -i tomcat-mysql

回收pv资源

  1. master节点删除tomcat命名空间
kubectl delete namespace tomcat
  1. master节点查看pv处于回收状态,会创建一个pod用来回收(镜像在Google仓库)
kubectl get pv
kubectl get pod
  1. master节点修改镜像地址为阿里云源
kubectl edit pod recycler-for-pv3
    image: registry.aliyuncs.com/google_containers/busybox:latest
  1. master节点查看pod正常运行
kubectl get pod
  1. master节点查看pv回收完毕,处于正常状态
kubectl get pv

标签选择器(优先)

  1. master节点创建pv配置文件
cat > /root/k8s_yaml/volume/pv4.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv4
  labels:
    type: sata
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: "/data/pv4"
    server: 10.0.0.11
    readOnly: false
EOF
  1. master节点创建pv资源
kubectl create -f pv4.yaml
  1. master节点查看pv资源的标签
kubectl get pv --show-labels
  1. master节点创建pvc配置文件:使用标签选择器
cat > /root/k8s_yaml/volume/mysql_pvc2.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: tomcat-mysql
spec:
  selector:
    matchLabels:
      type: ssd
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
EOF
  1. master节点创建pvc资源
kubectl create -f mysql_pvc2.yaml
  1. master节点验证pv资源优先使用标签选择器的指定
kubectl get pv --show-labels

Ceph

Storage:

  • 存储硬件:nas,san

  • 存储软件:nfs,lvm

Storage方式

  • 块存储:提供硬盘,lvm,cinder
  • 文件存储:提供目录,nfs(单机存储),glusterfs(分布式存储)
  • 对象存储:提供接口,fastdfs,Swift,ceph(分布式存储)
存储方式 技术实现 优势 劣势 代表作
块存储 裸盘上划分逻辑卷,逻辑卷格式化成任意文件系统 支持多种文件系统,传输速度快,提供硬件容错机制 无法实现网络共享 FC-SAN,iSCSI
文件存储 在格式化的磁盘上存储文件 提供网络共享 网络传输速度制约读写速度,分层目录结构限制可扩展性 NFS,FAT,EXT3
对象存储 以灵活可定制的对象为存储单元,元数据服务器提供快速并发寻址 读写速度较快的同时支持网络共享,对象灵活定义 管理软件的购买、使用和运维成本高 Swift

块存储

典型设备: 磁盘阵列,硬盘

块存储主要是将裸磁盘空间整个映射给主机使用的。

通过划逻辑盘、做Raid、或者LVM(逻辑卷)等种种方式逻辑划分出N个逻辑的硬盘。

接着块存储会采用映射的方式将这几个逻辑盘映射给主机,操作系统还需要对挂载的裸硬盘进行分区、格式化后,才能使用,与平常主机内置硬盘的方式完全无异。

优点:

  1. 通过了Raid与LVM等手段,对数据提供了保护。

  2. 将多块廉价的硬盘组合起来,成为一个大容量的逻辑盘对外提供服务,提高了容量。

  3. 可以并行写入,提升读写效率。

  4. 很多时候块存储采用SAN架构组网,传输速率以及封装协议的原因,使得传输速度与读写速率得到提升。

缺点:

  1. 采用SAN架构组网时,需要额外为主机购买光纤通道卡,还要买光纤交换机,成本高。

  2. 主机之间的数据无法共享。不利于不同操作系统主机间的数据共享。


文件存储

典型设备:FTP、NFS服务器

为了克服块存储中文件服务共享的问题,所以有了文件存储。

主机A可以直接对文件存储进行文件的上传下载,与块存储不同,主机A是不需要再对文件存储进行格式化的,因为文件管理功能已经由文件存储自己搞定了。

优点:

  • 造价低:随便一台机器,普通以太网就可以,不需要SAN网络。

  • 方便文件共享:针对块存储中文件无法共享问题,使用文件存储,第三方进行中转。

缺点:

  • 读写速率低,传输速率慢:以太网,上传下载速度较慢;另外所有读写都要1台服务器里面的硬盘来承担,相比起磁盘阵列动不动就几十上百块硬盘同时读写,速率慢了许多。

对象存储

典型设备:内置大容量硬盘的分布式服务器

对象存储最常用的方案,就是多台服务器内置大容量硬盘,再装上对象存储软件,然后搞几台服务器作为管理节点,安装上对象存储管理软件。管理节点可以管理其他服务器对外提供读写访问功能。

块存储读写快,不利于共享,文件存储读写慢,利于共享。能否搞一个读写快,利于共享的出来呢?于是有了对象存储。对象存储结合了块存储与文件存储的优点。

对象存储中,OSD(Object-based Storage Device)是对象存储设备,MDS(Metadata Server)是元数据服务器。

对象存储的原理

首先,一个文件包含了属性(术语叫metadata,元数据,例如该文件的大小、修改时间、存储路径等)以及内容(以下简称数据)。

以往像FAT32这种文件系统,是直接将一份文件的数据与metadata一起存储的,存储过程先将文件按照文件系统的最小块大小来打散(如4M的文件,假设文件系统要求一个块4K,那么就将文件打散成1000个小块),再写进硬盘里面,过程中没有区分数据/metadata的。而每个块最后会告知你下一个要读取的块的地址,然后一直这样顺序地按图索骥,最后完成整份文件的所有块的读取。

对象存储将元数据独立出来,控制节点叫元数据服务器(服务器+对象存储管理软件),里面主要负责存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息),而其他负责存储数据的分布式服务器叫做OSD,主要负责存储文件的数据部分。当用户访问对象,会先访问元数据服务器,元数据服务器只负责反馈对象存储在那些OSD,假设反馈文件A存储在B、C、D三台OSD,那么用户就会再次直接访问3台OSD服务器去读取数据。

这时候由于是3台OSD同时对外传输数据,所以传输的速度就加快了。当OSD服务器数量越多,这种读写速度的提升就越大,通过这种方式,实现了读写快的目的。

另一方面,对象存储软件是有专门的文件系统的,所以OSD对象又相当于文件服务器,那么就不存在文件共享方面的困难了,也就解决了文件共享方面的问题。


总结

  • 块存储可以认为是裸盘,最多包一层逻辑卷(LVM);常见的DAS、FC-SAN、IP-SAN都是块存储,块存储最明显的特征就是不能被操作系统直接读写,需要格式化为指定的文件系统(Ext3、Ext4、NTFS)后才可以访问。优点:读写快(带宽&IOPS);缺点:因为太底层了,不利于扩展。

  • 文件存储:指的是在文件系统上的存储,也就是主机操作系统中的文件系统。

  • 对象存储,对象存储肯定是分布式存储,但分布式存储可能是分布式文件系统,不一定是对象存储;常见的对象存储开源实现有 Ceph 的RADOS、openstack的swift、AWS s3等,常见分布式文件系统,lustre、glusterfs、HDFS等;对象存储和分布式文件系统的表面区别:对象存储支持的访问接口基本都是restful接口、而分布式文件系统提供的POSIX兼容的文件操作接口;

分布式文件系统和对象存储最本质的区别

分布式文件系统文件组织方式为目录树、对象存储采用的则是扁平的组织方式;对象存储不支持随机读取和写入,put和get操作都是针对的整个文件。


Ceph 简介

Ceph 独一无二地在一个统一的系统中同时提供了对象、块、和文件存储功能

它可靠性高、管理简单,并且是开源软件。 Ceph 的强大可以改变您公司的 IT 基础架构和海量数据管理能力。

Ceph 可提供极大的伸缩性——供成千用户访问 PB 乃至 EB 级的数据。 Ceph 节点以普通硬件和智能守护进程作为支撑点, Ceph 存储集群组织起了大量节点,它们之间靠相互通讯来复制数据、并动态地重分布数据。

Ceph 官方文档

Ceph 中文文档

CEPH 对象存储

  • REST 风格的接口
  • 与 S3 和 Swift 兼容的 API
  • S3 风格的子域
  • 统一的 S3/Swift 命名空间
  • 用户管理
  • 利用率跟踪
  • 条带化对象
  • 云解决方案集成
  • 多站点部署
  • 灾难恢复

CEPH 块设备

  • 瘦接口支持
  • 映像尺寸最大 16EB
  • 条带化可定制
  • 内存缓存
  • 快照
  • 写时复制克隆
  • 支持内核级驱动
  • 支持 KVM 和 libvirt
  • 可作为云解决方案的后端
  • 增量备份

CEPH 文件系统

  • 与 POSIX 兼容的语义
  • 元数据独立于数据
  • 动态重均衡
  • 子目录快照
  • 可配置的条带化
  • 有内核驱动支持
  • 有用户空间驱动支持
  • 可作为 NFS/CIFS 部署
  • 可用于 Hadoop (取代 HDFS)

Ceph 特点

高性能

  • 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。
  • 考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。
  • 能够支持上千个存储节点的规模,支持TB到PB级的数据。

高可用性

  • 副本数可以灵活控制。
  • 支持故障域分隔,数据强一致性。
  • 多种故障场景自动进行修复自愈。
  • 没有单点故障,自动管理。

高可扩展性

  • 去中心化。
  • 扩展灵活。
  • 随着节点增加而线性增长。

特性丰富

  • 支持三种存储接口:块存储、文件存储、对象存储。
  • 支持自定义接口,支持多种语言驱动。

Ceph 体系结构

stack

stack - 中文

img


Ceph 基础组件

构成 ceph 集群的基础组件:OSD、Manager、MDS、Monitor。

  • OSD(ceph-osd):object storage daemon,对象存储进程。ceph 管理物理硬盘时,引入了OSD概念,每一块盘都会针对的运行一个OSD进程。换句话说,ceph 集群通过管理 OSD 来管理物理硬盘。OSD 一般功能为:存储数据、维护数据副本、数据恢复、数据再平衡以及对ceph monitor组件提供相关监控信息。

  • Manager(ceph-mgr):用于收集ceph集群状态、运行指标,比如存储利用率、当前性能指标和系统负载。对外提供 ceph dashboard(ceph ui)和 resetful api。Manager组件开启高可用时,至少2个。

  • Monitor(ceph-mon):维护集群的状态,包含monitor组件信息,manger 组件信息,osd组件信息,mds组件信息,crush 算法信息。还负责ceph集群的身份验证功能,client在连接ceph集群时通过此组件进行验证。Monitor组件开启高可用时,至少3个。

  • MDS(ceph-mds):Metadata server,元数据服务。为ceph 文件系统提供元数据服务(ceph 对象存储和块存储不需要MDS)。为 posix 文件系统用户提供性能良好的基础命令(ls,find等)。


创建Ceph 存储,至少需要以下服务:

  1. 一个Ceph Monitor
  2. 两个OSD守护进程

img


Ceph IO算法流程

img

File是用户需要读写的文件。File->Object映射:

  • ino (File的元数据,File的唯一id)。
  • ono(File切分产生的某个object的序号,默认以4M切分一个块大小)。
  • oid(object id: ino + ono)。

Object是RADOS需要的对象。Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。Object->PG映射:

  • hash(oid) & mask-> pgid 。
  • mask = PG总数m(m为2的整数幂)-1 。

PG(Placement Group)用于对object的存储进行组织和位置映射, (类似于redis cluster里面的slot的概念) 一个PG里面会有很多object。采用CRUSH算法,将pgid代入其中,然后得到一组OSD。PG->OSD映射:

  • CRUSH(pgid)->(osd1,osd2,osd3) 。

OSD(Object Storage Device)对象存储设备:物理或逻辑存储单元(如LUN)。有时,Ceph用户使用术语“OSD”来指代Ceph OSD守护进程,尽管正确的术语是“Ceph OSD”。


Ceph IO伪代码流程

locator = object_name
obj_hash =  hash(locator)
pg = obj_hash % num_pg
osds_for_pg = crush(pg)  # returns a list of osds
primary = osds_for_pg[0]
replicas = osds_for_pg[1:]

参考文档:


部署Ceph集群

Ceph 集群架构

使用ceph-deploy部署nautilus版Ceph

  • 3个Ceph Monitor
  • 3个Ceph OSD

image-20201210164254751

环境准备

主机名 IP 配置
ceph01 10.0.0.14 1核1G,额外硬盘sdb单个文件50G
ceph02 10.0.0.15 1核1G,额外硬盘sdb单个文件50G
ceph03 10.0.0.16 1核1G,额外硬盘sdb单个文件50G
  • 关闭:selinuxfirewalldNetworkManagerpostfix(非必须)

  • 修改IP地址、主机名

hostnamectl set-hostname 主机名
sed -i 's/200/IP/g' /etc/sysconfig/network-scripts/ifcfg-eth0
  • 添加hosts解析
cat >> /etc/hosts <<EOF
10.0.0.14 ceph01
10.0.0.15 ceph02
10.0.0.16 ceph03
EOF
  • 如果热添加硬盘,需要扫描发现硬盘
echo '- - -' >/sys/class/scsi_host/host0/scan
echo '- - -' >/sys/class/scsi_host/host1/scan
echo '- - -' >/sys/class/scsi_host/host2/scan
fdisk -l
  • 准备yum源:Base epel ceph
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
cat > /etc/yum.repos.d/ceph.repo <<EOF
[ceph_x86]
name=ceph_x86
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/x86_64/
gpgcheck=0

[ceph_noarch]
name=ceph_noarch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/noarch/
gpgcheck=0
EOF

如果你想保留rpm的话,可以开启缓存。

vim /etc/yum.conf
... ...
keepcache=1 # 开启缓存
... ...

打包缓存

mkdir ceph_rpm
find /var/cache/yum -type f -name "*.rpm" | xargs mv -t ceph_rpm
tar zcf ceph_rpm.tar.gz ceph_rpm

ceph-deploy节点

  1. 配置ssh密钥免密登录所有节点
ssh-keygen
ssh-copy-id root@ceph01
ssh-copy-id root@ceph02
ssh-copy-id root@ceph03

注意: 如果SSH不使用默认22端口时

cat > ~/.ssh/config <<EOF
Port 12345
EOF
  1. 安装ceph-deploy
yum install ceph-deploy -y

所有节点安装

yum install ceph ceph-mon ceph-mgr ceph-radosgw.x86_64 ceph-mds.x86_64 ceph-osd.x86_64 -y

ceph-deploy使用其内置官网源安装,非常慢!!!因此要提前装好所需包。


ceph-deploy部署ceph集群

  1. ceph-deploy初始化集群配置文件
cd /root
mkdir ceph-deploy && cd ceph-deploy
ceph-deploy new --public-network 10.0.0.0/24 ceph01 ceph02 ceph03

默认[--cluster-network CLUSTER_NETWORK]=[--public-network PUBLIC_NETWORK]

生产中建议--cluster-network使用万兆带宽网络。

  1. 初始化集群:部署ceph-monitor并启动
ceph-deploy mon create-initial

在各节点生成配置文件/etc/ceph

  1. 创建管理员用户:生成并推送管理员密钥
ceph-deploy admin ceph01 ceph02 ceph03
  1. 查看集群状态:mon存在
ceph -s
  1. 部署ceph-manager并启动
ceph-deploy mgr create ceph01 ceph02 ceph03
  1. 查看集群状态:mon和mgr存在
ceph -s
  1. 创建osd
ceph-deploy osd create ceph01 --data /dev/sdb
ceph-deploy osd create ceph02 --data /dev/sdb
ceph-deploy osd create ceph03 --data /dev/sdb

data:数据盘路径

journal:日志盘路径,日志盘(ssd)越快,ceph越快。尤其是小块数据I/O,提速明显。

  1. 查看集群状态:mon和mgr和osd存在
ceph -s

如果状态有健康警告如下:

[root@ceph01 ceph-deploy]# ceph -s
cluster:
id:     a4f16e95-ba09-49f5-b0bf-ada31833a457
health: HEALTH_WARN
   clock skew detected on mon.ceph03

services:
mon: 3 daemons, quorum ceph01,ceph02,ceph03 (age 23m)
mgr: ceph01(active, since 53m), standbys: ceph02, ceph03
osd: 3 osds: 3 up (since 29m), 3 in (since 29m)

data:
pools:   0 pools, 0 pgs
objects: 0 objects, 0 B
usage:   3.0 GiB used, 147 GiB / 150 GiB avail
pgs:

生产环境请使用ntp服务


测试环境可以调整ceph配置中的[global]下时间偏差阈值:

cat >> /root/ceph-deploy/ceph.conf <<EOF
mon clock drift allowed = 2
mon clock drift warn backoff = 30
EOF

向所有同步的mon节点推送配置文件,重启mon服务:

ceph-deploy --overwrite-conf config push ceph0{1,2,3}
systemctl restart ceph-mon.target

最后查看集群状态:HEALTH_OK

  1. 查看monitors信息
ceph mon dump

ceph 资源配置

  1. 创建pool资源池
ceph osd pool create k8s 128 128
  1. 查看pool资源池
ceph osd pool ls
ceph osd pool stats k8s
  1. 调整pool资源池的ps数量
ceph osd pool set k8s pg_num 128
  1. 创建RBD块设备
rbd create --size 1024 k8s/tomcat_mysql.img
  1. 查看RBD块设备
rbd info k8s/tomcat_mysql.img
rbd info --pool k8s tomcat_mysql.img
rbd info --pool k8s --image tomcat_mysql.img
  1. 查看OSD节点数量
ceph osd pool get k8s size

增加OSD节点会自动进行数据整合,请在业务低谷期间增加,一台一台慢慢加。

  1. 查看RBD块设备所有对象
rados -p k8s ls
rados -p k8s ls | grep rbd_data.ac74b202ed1a
rados -p k8s ls | grep rbd_data.ac74b202ed1a | wc -l

用多少,分多少。

  1. 树状显示所有OSD
ceph osd tree

使用RBD块设备

  1. 禁用高级特性
rbd feature disable k8s/tomcat_mysql.img object-map fast-diff deep-flatten
  1. 映射到实际设备
rbd map k8s/tomcat_mysql.img

关机映射失效,需要重新映射,数据不会丢失。

  1. 格式化
mkfs.xfs /dev/rbd0
  1. 挂载
mount /dev/rbd0 /mnt
  1. 卸载
umount /mnt
  1. 扩容
rbd resize --size 2048 k8s/tomcat_mysql.img
  1. 挂载
mount /dev/rbd0 /mnt
  1. 调整容量
xfs_growfs /dev/rbd0
  1. 挂载,查看
df -Th

Ceph 对接 k8s

Ceph RBD 对接 k8s :参考官方文档


准备

所有k8s node节点安装ceph-common

cat > /etc/yum.repos.d/ceph.repo <<EOF
[ceph_x86]
name=ceph_x86
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/x86_64/
gpgcheck=0

[ceph_noarch]
name=ceph_noarch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/noarch/
gpgcheck=0
EOF
yum -y install ceph-common

ceph01

  1. 推送ceph用户密钥文件和配置文件给所有k8s node节点
scp -rp /etc/ceph/ceph.client.admin.keyring root@10.0.0.12:/etc/ceph/
scp -rp /etc/ceph/ceph.client.admin.keyring root@10.0.0.13:/etc/ceph/
scp -rp /etc/ceph/ceph.conf root@10.0.0.12:/etc/ceph/
scp -rp /etc/ceph/ceph.conf root@10.0.0.13:/etc/ceph/
  1. 获取base64加密的ceph用户key
grep key /etc/ceph/ceph.client.admin.keyring |awk '{printf "%s", $NF}'|base64
  1. 创建最小特性镜像
rbd create --size 2048 --image-feature layering k8s/test.img
rbd ls -p k8s

k8s-master

  1. master节点编写Secret资源yaml
mkdir -p /root/k8s_yaml/ceph && cd /root/k8s_yaml/ceph
cat > /root/k8s_yaml/ceph/ceph-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
  namespace: tomcat
  name: ceph-secret
type: "kubernetes.io/rbd"
data:
  key: QVFDYTV0RmY3ZVBlQWhBQU45aU1ONHFYdUhNNkRGZ2pCOTJMUFE9PQ==
EOF
  1. master节点创建Secret资源
kubectl create namespace tomcat
kubectl create -f ceph-secret.yaml
  1. master节点查看Secret资源
kubectl get secret -n tomcat
  1. master节点查看Secret资源配置文件
kubectl get secret -n tomcat ceph-secret -o yaml

能看到ceph用户key,可以解密。


pod 对接ceph rbs存储

查看解释

kubectl explain pod.spec.volumes.rbd
  1. master节点编写Pod资源yaml
cat > /root/k8s_yaml/ceph/test_ceph_pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  namespace: tomcat
  name: rbd
spec:
  containers:
    - image: 10.0.0.11:5000/nginx:1.13
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /data
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.0.0.14:6789'
        - '10.0.0.15:6789'
        - '10.0.0.16:6789'
        pool: k8s
        image: test.img
        fsType: ext4
        user: admin
        keyring: /etc/ceph/keyring
        secretRef:
          name: ceph-secret
EOF
  1. master节点创建Pod资源
kubectl create -f test_ceph_pod.yaml
  1. master节点查看Pod资源
kubectl get pod -o wide -n tomcat
  1. master节点进入容器,查看有/dev/rbd0设备,验证对接成功
kubectl exec -n tomcat -it rbd /bin/bash
df -h
  1. node节点查看所有映射的rbd
rbd device ls

pv 对接ceph rbs存储

  1. master节点编写PV资源yaml
cat > /root/k8s_yaml/ceph/ceph_pv1.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: ceph01
  labels:
    type: rbd
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  rbd:
    monitors:
    - '10.0.0.14:6789'
    - '10.0.0.15:6789'
    - '10.0.0.16:6789'
    pool: k8s
    image: test2.img
    fsType: xfs
    user: admin
    secretRef:
      name: ceph-secret
EOF

注意:请使用xfs格式。

ext4格式默认创建一个lost+found目录,导致mysql无法启动。

  • 需要手动删除

    df -Th|grep rbd
    rm -fr /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/k8s-image-test2.img/*
    
  • 或者使用initContainer配置项,参考文档

  1. ceph创建最小特性镜像
rbd create --size 2048 --image-feature layering k8s/test2.img
rbd ls -p k8s
  1. master节点创建pv资源
kubectl create -f ceph_pv1.yaml
  1. master节点查看pv资源
kubectl get pv -o wide
  1. master节点编写PVC资源yaml
cat > /root/k8s_yaml/ceph/ceph_pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: tomcat-rbd1
  namespace: tomcat
spec:
  selector:
    matchLabels:
      type: rbd
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
EOF
  1. master节点创建pvc资源
kubectl create -f ceph_pvc.yaml
  1. master节点查看pvc资源
kubectl get pvc -n tomcat -o wide
  1. master节点编写Deployment资源yaml
cat > /root/k8s_yaml/ceph/mysql-deploy.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: tomcat
  name: mysql
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      volumes:
      - name: mysql
        persistentVolumeClaim:
          claimName: tomcat-rbd1
      containers:
        - name: wp-mysql
          image: 10.0.0.11:5000/mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'
EOF
  1. master节点创建Deployment资源
kubectl create -f mysql-deploy.yaml
  1. master节点查看Deployment资源
kubectl get pod -n tomcat -o wide

Jenkins实现k8s持续更新

环境准备

主机名 IP 服务 内存
k8s-master 10.0.0.11 kube-apiserver 8080 1G
k8s-node-1 10.0.0.12 kube-apiserver 8080 1G
k8s-node-2 10.0.0.13 Jenkins(tomcat + jdk) 8080 2G
  • 代码仓库使用gitee托管

image-20201211160845138


gitee仓库准备

  1. 创建远程仓库

image-20201211112433786

  1. Git 全局设置:
git config --global user.name "卜算子"
git config --global user.email "wuqi83417883@163.com"
  • 新仓库:
mkdir oldboy
cd oldboy
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin https://gitee.com/busuanzi/oldboy.git
git push -u origin master
  • 已有仓库:
cd /opt
git clone https://gitee.com/kangjie1209/monitor.git
git remote remove origin
git remote add origin https://gitee.com/busuanzi/oldboy.git
git push -u origin master

jenkins部署(k8s-node-2)

  1. 准备Jenkins + tomcat + jdk
cd /opt
for n in apache-tomcat-8.0.27.tar.gz jdk-8u102-linux-x64.rpm jenkin-data.tar.gz jenkins.war;do wget http://192.168.15.253/k8s_jenkins/$n ;done
  1. 二进制安装jenkins
rpm -ivh jdk-8u102-linux-x64.rpm 
mkdir /app -p
tar xf apache-tomcat-8.0.27.tar.gz -C /app
rm -fr /app/apache-tomcat-8.0.27/webapps/*
mv jenkins.war /app/apache-tomcat-8.0.27/webapps/ROOT.war
tar xf jenkin-data.tar.gz -C /root
/app/apache-tomcat-8.0.27/bin/startup.sh 
netstat -lntup

jenkins构建测试

  1. 访问jenkins:http://10.0.0.12:8080/,默认账号密码 admin:123456
  2. 创建一个新任务

image-20201211120409267

  1. 配置jenkins拉取gitlab代码凭据

image-20201211120743488

image-20201211120622384

  1. 构建Shell测试

image-20201211121051759

  1. 立即构建

image-20201211121150223

  1. 查看控制台输出

image-20201211121329046


构建docker镜像

  1. docker镜像基础包:nginx:1.13

  2. 编写dockerfile.dockerignore并运行测试

cat > dockerfile <<EOF
FROM 10.0.0.11:5000/nginx:1.13
RUN rm -rf /usr/share/nginx/html/*
ADD . /usr/share/nginx/html
EOF
echo dockerfile > .dockerignore
docker build -t test:v1 .
docker run -d -p 80:80 test:v1
  1. 浏览器访问http://10.0.0.12/

  2. 上传dockerfile.dockerignore到私有仓库

git add .dockerignore dockerfile
git commit -m "add dockerfile"
git push -u origin master
  1. gitee添加标签v1,修改首页,添加标签v2
  2. master节点手动发布
kubectl create namespace oldboy
kubectl run -n oldboy oldboy --image=10.0.0.11:5000/oldboy:v1 --replicas=2
kubectl expose -n oldboy deploy oldboy --type=NodePort --port=80 --target-port=80
kubectl get all -n oldboy

jenkins滚动更新

  1. 使用参数构建

image-20201211150942890

  1. 修改Shell
docker build -t 10.0.0.11:5000/oldboy:$version .
docker push 10.0.0.11:5000/oldboy:$version
kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:$version

image-20201211152147688

  1. 执行测试

Build with Parameters --> 输入版本 --> 开始构建

jenkins从gitee下载代码,构建docker镜像并上传到私有仓库,调用k8s滚动发布。

  1. 查看控制台输出

image-20201211151931346

  1. shell脚本
if [ -f /tmp/oldboy.lock ];then
    docker build -t 10.0.0.11:5000/oldboy:v$version .
    docker push 10.0.0.11:5000/oldboy:v$version
    kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:v$version
    port=`kubectl -s 10.0.0.11:8080  get svc -n oldboy|grep -oP '(?<=80:)\d+'`
    echo "你的项目地址访问是http://10.0.0.13:$port"
    echo "更新成功"
else
    docker build -t 10.0.0.11:5000/oldboy:v$version  .
    docker push 10.0.0.11:5000/oldboy:v$version
    kubectl -s 10.0.0.11:8080 create namespace oldboy
    kubectl -s 10.0.0.11:8080 run oldboy -n oldboy  --image=10.0.0.11:5000/oldboy:v$version --replicas=3 --record
    kubectl -s 10.0.0.11:8080 expose -n oldboy deployment oldboy --port=80 --type=NodePort
    port=`kubectl -s 10.0.0.11:8080  get svc -n oldboy|grep -oP '(?<=80:)\d+'`
    echo "你的项目地址访问是http://10.0.0.13:$port"
    echo "发布成功"
    touch /tmp/oldboy.lock
    chattr +i /tmp/oldboy.lock
fi

jenkins一键回滚

另建一个工程,不需要拉代码,仅仅需要指定版本参数和shell,参数化回滚:

kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:$version

k8s高可用

架构

image-20201211174520119

主机名 IP 服务
k8s-master01 10.0.0.11 api-server,controller-manager,scheduler,etcd,keepalived,flannel
k8s-master02 10.0.0.12 api-server,controller-manager,scheduler,etcd,keepalived,flannel
k8s-node-1 10.0.0.13 kubernetes-node,flannel

etcd高可用集群

不能单机扩集群,首次使用请使用集群,集群是奇数个,竞选。(虚拟机请还原快照)

  1. 所有节点安装
yum install etcd -y
  1. 所有节点配置
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node1"  # 节点的名字
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.11:2380" # 节点同步数据的地址
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.11:2379"       # 节点提供服务的地址
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380"               # 初始化集群
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"  # 初始化集群令牌
ETCD_INITIAL_CLUSTER_STATE="new"           # 初始化集群状态
cat > /etc/etcd/etcd.conf <<EOF
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node1"
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.11:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.11:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_STRICT_RECONFIG_CHECK="true"
#ETCD_ENABLE_V2="true"
#
#[Proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"
#
#[Security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_AUTO_TLS="false"
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""
#ETCD_PEER_AUTO_TLS="false"
#
#[Logging]
#ETCD_DEBUG="false"
#ETCD_LOG_PACKAGE_LEVELS=""
#ETCD_LOG_OUTPUT="default"
#
#[Unsafe]
#ETCD_FORCE_NEW_CLUSTER="false"
#
#[Version]
#ETCD_VERSION="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"
#
#[Profiling]
#ETCD_ENABLE_PPROF="false"
#ETCD_METRICS="basic"
#
#[Auth]
#ETCD_AUTH_TOKEN="simple"
EOF
# node2
sed -i "9c ETCD_NAME=\"node2\"" /etc/etcd/etcd.conf
sed -i "20c ETCD_INITIAL_ADVERTISE_PEER_URLS=\"http://10.0.0.12:2380\"" /etc/etcd/etcd.conf
sed -i "21c ETCD_ADVERTISE_CLIENT_URLS=\"http://10.0.0.12:2379\"" /etc/etcd/etcd.conf
# node3
sed -i "9c ETCD_NAME=\"node3\"" /etc/etcd/etcd.conf
sed -i "20c ETCD_INITIAL_ADVERTISE_PEER_URLS=\"http://10.0.0.13:2380\"" /etc/etcd/etcd.conf
sed -i "21c ETCD_ADVERTISE_CLIENT_URLS=\"http://10.0.0.13:2379\"" /etc/etcd/etcd.conf
  1. 所有节点同时启动,并加入开机自启
systemctl enable etcd
systemctl start etcd
  1. 检查集群健康状态和成员列表
etcdctl cluster-health
etcdctl member list

flannel配置

  1. 修改配置文件
sed -i "4c FLANNEL_ETCD_ENDPOINTS="http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379"" /etc/sysconfig/flanneld
  1. 创建key
etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16","Backend": {"Type": "vxlan"} }'
  1. 启动并加入开机自启
systemctl start flanneld
systemctl enable flanneld
systemctl restart docker
  1. 检查网卡
ip a

master节点

master01和master02部署api-server,controller-manager,scheduler

  1. 安装
yum install kubernetes-master -y
  1. 配置apiserver
sed -i "8c KUBE_API_ADDRESS=\"--insecure-bind-address=0.0.0.0\"" /etc/kubernetes/apiserver
sed -i "11c KUBE_API_PORT=\"--port=8080\"" /etc/kubernetes/apiserver
sed -i "14c KUBELET_PORT=\"--kubelet-port=10250\"" /etc/kubernetes/apiserver
sed -i "17c KUBE_ETCD_SERVERS=\"--etcd-servers=http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379\"" /etc/kubernetes/apiserver
sed -i "s/ServiceAccount,//" /etc/kubernetes/apiserver
  1. 配置config
sed -i "22c KUBE_MASTER=\"--master=http://127.0.0.1:8080\"" /etc/kubernetes/config
  1. 启动并加入开机启动
systemctl enable kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl start kube-apiserver.service
systemctl start kube-controller-manager.service
systemctl start kube-scheduler.service
  1. 检查服务是否安装正常
kubectl get componentstatus

Keepalived配置

在master01和master02安装keepalived。

  1. 安装
yum install keepalived -y
  1. master01配置
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived

global_defs {
   router_id LVS_DEVEL_11
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.10
    }
}
EOF
  1. master02配置
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived

global_defs {
   router_id LVS_DEVEL_12
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 80
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.10
    }
}
EOF
  1. 启动并加入开机自启
systemctl enable keepalived
systemctl start keepalived

node节点

所有node节点的kubelet,kube-proxy指向api-server的vip。

  1. 安装:见k8s集群yum安装
  2. 配置
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.10:8080\"" /etc/kubernetes/config
sed -i "14c KUBELET_API_SERVER=\"--api-servers=http://10.0.0.10:8080\"" /etc/kubernetes/kubelet
  1. 重启生效
systemctl restart kubelet.service kube-proxy.service

posted @ 2021-01-03 18:10  原因与结果  阅读(1223)  评论(0编辑  收藏  举报