锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

博哥爱运维教程&视频

时间:2023-02-15 17:30:00 4034连接器xg4afxd101套管式温度传感器连接器xf3h

文章目录

  • 第1关 K8s一窥真容
  • 第2关 部署安装包和系统环境准备
  • 第3关 可安装二进制高k8s生产级集群
  • 第4关 K8s最骄傲的弟弟Docker
  • 第5关 K8s攻克战略之一
    • **K8s的API对象(所有怪物角色列表)**
    • **Namespace**
    • **Pod**
  • 第5关 K8s攻克战略二-Deployment
    • **Deployment**
  • 第5关 K8s攻克战略3-服务pod的健康检测
    • **Health Check**
    • **Liveness**
    • **Readiness**
    • **maxSurge**
    • **maxUnavailable**
  • 第5关 k8s架构师课程攻克战略4-Service
    • **Service、Endpoint**
  • 第5关 k8s架构师课程攻克战略 - labels
    • Labels
  • 第6关 k8s架构师课程流量入口Ingress上部
    • **DaemonSet**
  • 第7关 k8s架构师课程之一HPA 自动水平伸缩pod
    • **HPA**
  • 第8关 k8s第一节架构师课程的持久存储
    • **Volume**
    • **emptyDir**
    • **hostPath**
  • 第8关 k8s第二节架构师课程的持久存储PV和PVC
  • 第8关 k8s架构师课程的持久存储StorageClass
    • **StorageClass**
  • 第9关 k8s架构师课程包括状态服务StatefulSet
    • StatefulSet
  • 第10关 k8s架构师课程的一次性和定期任务
    • Job, CronJob
    • job
    • cronjob
  • 第11关 k8s架构师课程之一RBAC角色访问控制
    • RBAC
  • 第12关 k8s架构师课程业务日志收集上节介绍,下节实战
    • 日志收集
  • 第13关 k8s私有镜像仓库架构师课程-Harbor
  • 第14关k8s架构师课程的业务Prometheus监控实战一
    • 服务监控
    • 实战操作篇一
  • 第14关k8s架构师课程的业务Prometheus监控实战二
    • 使用prometheus来监控ingress-nginx
    • 使用Prometheus监控二进制部署ETCD集群
  • 第14关k8s架构师课程的业务Prometheus监控实战三
    • prometheus监控数据和grafana配置持久存储配置
    • prometheus数据持久配置
    • grafana配置持久存储配置
  • 第14关k8s架构师课程的业务Prometheus监控实战四
    • prometheus发送报警
    • 附: 监控其他服务prometheus规则配置
  • 第15关 k8s基于架构师课程gitlab的CICD自动化二
    • 部署postgresql
    • 部署redis
  • 第15关 k8s基于架构师课程gitlab的CICD自动化三
    • 部署gitlab
    • 部署gitlab-tls
  • 第15关k8s架构师课程之基于gitlab的CICD自动化四
    • 部署gitlab-runner
  • 第15关k8s基于架构师课程gitlab的CICD自动化五
    • 增加gitlab在k8s的内部解析
    • 增加ssh端口转发
  • 第15关k8s基于架构师课程gitlab的CICD自动化六
    • 部署dind(docker in docker)
  • 第15关 k8s架构师课程之一CICD自动化devops大结局
    • CI/CD实战项目的生产
    • 快速生成kubernetes(k8s)的yaml四种配置方法
  • 快速生成k8s的yaml四种配置方法
  • 关于K8S服务健康检测方法补充说明

下载视频教程:

链接:https://pan.baidu.com/s/1rAMDFPwda4Pl3wO2DsGh1w

提取码:txpy

第1关 K8s一窥真容

首先是简结版K8s架构图

第1关 K8s一窥真容

接着来一张详细的K8s架构图

从上图可以看出整个画面K8s集群分为两部分:

  • K8s控制平面
  • (工作)节点

让我们具体看看这两部分做了什么,内部操作是什么。

控制平面组件

控制平面负责控制并使得整个K8s集群运行正常。 控制平面包含以下组件:

  • ETCD分布式持久存储 – etcd保存了整个K8s集群状态;
  • API服务器 – apiserver提供认证、授权、访问控制等资源运营的唯一入口API注册发现等机制;
  • 调度器 – scheduler负责资源调度,按照预定的调度策略Pod调度到相应的机器;
  • 控制器管理器 – controller manager负责维护故障检测、自动扩展、滚动更新等集群状态;

这些组件用于存储和管理集群状态,但它们不是操作应用程序的容器。

工作节点上运行的组件

运行容器的任务依赖于每个工作节点上运行的组件:

  • Kubelet – 是 Node 的 agent,负责维护容器的生命周期和生命周期Volume(CSI)和网络(CNI)的管理;
  • Kubelet服务代理(kube-proxy) – 负责为Service提供cluster内部服务发现与负载平衡;
  • 容器运行时(Docker、rkt或者其他) – Container runtime负责镜像管理和Pod以及容器的真实运行(CRI);

附加组件

除了控制平面(和节点上运行的组件)外,还有几个附加组件才能提供所有之前讨论的功能。包含:

  • K8s DNS服务器 – CoreDNS负责为整个集群提供DNS服务
  • 仪表板(可选) – Dashboard提供GUI,作为高级运维人员,使用kubectl命令行工具管理足矣
  • Ingress控制器 – Ingress Controller为服务提供外网流量入口
  • 容器集群监控 – Metrics-server为K8s资源指标获取工具; Prometheus提供资源监控
  • CNI容器网络接口插件 – calico, flannel(如果没有实施网络策略的需求,那么就直接用flannel,开箱即用;否则就用calico了,但要注意如果网络使用了巨型帧,那么注意calico配置里面的默认值是1440,需要根据实际情况进行修改才能达到最佳性能)

简单概括

API服务器只做了存储资源到etcd和通知客户端有变更的工作。 调度器则只是给pod分配节点(由kubelet来启动容器) 控制管理器里的控制器始终保持活跃的状态,来确保系统真实状态朝API服务器定义的期望的状态收敛

Deployment资源提交到API服务器的事件链

准备包含Deployment清单的YAML文件,通过kubectl提交到Kubernetes。kubectl通过HTTP POST请求发送清单到Kubernetes API服务器。API服务器检查Deployment定义,存储到etcd,返回响应给kubectl,如下图所示:

第2关 部署安装包及系统环境准备

下面是相关软件安装包及系统镜像下载地址

# VMware Workstation15
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1027984&highlight=vmware%2B15.5.0

# CentOS-7.9-2009-x86_64-Minimal
https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso

安装centos7这块不算很复杂,作为想学习k8s的同学,是有必要打好linux系统这些基本功的,相关安装教程百度下也会有很多,我这里就不再重复写相关安装教程了。

这里我就先啰嗦两句… 看了下现在市面上很多k8s相关的视频教程,光说将安装就占去整个教程一半以上的时间,剩下真正生产实战的时间寥寥无几。 当然我这里并不是说这种方式有什么大问题,我只是根据我自己的快速学习及生产实践来给大家做下分享,希望的是大家少走,能更快速的在工作生产中上手使用k8s。 k8s的安装,我的工作生产实践经验是选取开源的二进制包的形式来安装,正所谓工欲善其事必先利其器,我们先用成熟的工具把符合生产标准的k8s集群给部署起来,边实战边理解k8s各个组成部分的原理,这样会达到事半功倍的效果,并且现在实际情况是各种云平台都推出了自家的k8s托管服务,你连搭建都不需要了,直接买机器它就帮你部署好了,直接用就行。这也好比你想开车,不一定非得自己先把车的所有组件及运行原理、还有维修手段都掌握了再买辆车开吧,估计人都没兴趣去开车了。真实生活中,大家大部分都是拿了驾照就直接去买车,开起来体验再说,在开的过程中,慢慢学会了一些汽车的保养知识。 然后开始讲解工具安装步骤。。。

为什么要学习K8s呢? k8s是容器编排管理平台,满足了大量使用docker容器的一切弊端,如果还非要说出为什么要学习掌握k8s,我只能说未来几年,k8s是基本所有互联网企业的技术平台会使用的技术,不会就只能被淘汰 或者拿不到自己满意的高薪。

第3关 二进制高可用安装k8s生产级集群

下面是这次安装k8s集群相关系统及组件的详细版本号

  • CentOS Linux release 7.9.2009 (Core)
  • k8s: v.1.20.2
  • docker: 19.03.14
  • etcd: v3.4.13
  • coredns: v1.7.1
  • cni-plugins: v0.8.7
  • calico: v3.15.3

下面是此次虚拟机集群安装前的IP等信息规划,这里大家就按我教程里面的信息来做,等第一遍跑通了后,后面可以按照自己的需求改变IP信息,这时候大家就会比较顺利了

IP hostname role
10.0.1.201【100.50】 node-1【master】 master/work node
10.0.1.202 node-2 master/work node
10.0.1.203【100.60】 node-3【node】 work node
10.0.1.204 node-4 work node

显然目前为止,前面几关给我们的装备还不太够,我们继续在这一关获取充足的装备弹药,为最终战胜K8s而奋斗吧!

这里采用开源项目https://github.com/easzlab/kubeasz,以二进制安装的方式,此方式安装支持系统有CentOS/RedHat 7, Debian 9/10, Ubuntu 1604/1804。

部署网络架构图

安装步骤清单:

  1. deploy机器做好对所有k8s node节点的免密登陆操作
  2. deploy机器安装好python2版本以及pip,然后安装ansible
  3. 对k8s集群配置做一些定制化配置并开始部署

对于这个开源项目,我自己编写了一个shell脚本对其进行了一层封装,说简单点就是想偷点懒o,这里我就以这个脚本来讲解整个安装的步骤:

将下面脚本内容复杂到k8s_install_new.sh脚本内准备执行安装

如果在这里面不好复杂的话,可以直接到我的github仓库里面下载这个脚本,地址:
https://github.com/bogeit/LearnK8s/blob/main/k8s_install_new.sh

#!/bin/bash
# auther: boge
# descriptions:  the shell scripts will use ansible to deploy K8S at binary for siample

# 传参检测
[ $# -ne 6 ] && echo -e "Usage: $0 rootpasswd netnum nethosts cri cni k8s-cluster-name\nExample: bash $0 bogedevops 10.0.1 201\ 202\ 203\ 204 [containerd|docker] [calico|flannel] test\n" && exit 11 

# 变量定义
export release=3.0.0
export k8s_ver=v.1.20.2  # v1.20.2, v.1.19.7, v1.18.15, v1.17.17
rootpasswd=$1
netnum=$2
nethosts=$3
cri=$4
cni=$5
clustername=$6
if ls -1v ./kubeasz*.tar.gz &>/dev/null;then software_packet="$(ls -1v ./kubeasz*.tar.gz )";else software_packet="";fi
pwd="/etc/kubeasz"


# deploy机器升级软件库
if cat /etc/redhat-release &>/dev/null;then
    yum update -y
else
    apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y
    [ $? -ne 0 ] && apt-get -yf install
fi

# deploy机器检测python环境
python2 -V &>/dev/null
if [ $? -ne 0 ];then
    if cat /etc/redhat-release &>/dev/null;then
        yum install gcc openssl-devel bzip2-devel 
        wget https://www.python.org/ftp/python/2.7.16/Python-2.7.16.tgz
        tar xzf Python-2.7.16.tgz # ?? tar xvf Python-2.7.16.tgz
        cd Python-2.7.16
        ./configure --enable-optimizations
        make install
        ln -s -f /usr/bin/python2.7 /usr/bin/python
        cd -
    else
        apt-get install -y python2.7 && ln -s -f /usr/bin/python2.7 /usr/bin/python
    fi
fi

# deploy机器设置pip安装加速源
if [[ $clustername != 'aws' ]]; then
mkdir ~/.pip
cat > ~/.pip/pip.conf </dev/null;then
    yum install git python-pip sshpass -y
    [ -f ./get-pip.py ] && python ./get-pip.py || {
    wget https://bootstrap.pypa.io/pip/2.7/get-pip.py && python get-pip.py
    }
else
    apt-get install git python-pip sshpass -y
    [ -f ./get-pip.py ] && python ./get-pip.py || {
    wget https://bootstrap.pypa.io/pip/2.7/get-pip.py && python get-pip.py
    }
fi
python -m pip install --upgrade "pip < 21.0"

pip -V
pip install --no-cache-dir ansible netaddr


# 在deploy机器做其他node的ssh免密操作
for host in `echo "${nethosts}"`
do
    echo "============ ${netnum}.${host} ===========";

    if [[ ${USER} == 'root' ]];then
        [ ! -f /${USER}/.ssh/id_rsa ] &&\
        ssh-keygen -t rsa -P '' -f /${USER}/.ssh/id_rsa
    else
        [ ! -f /home/${USER}/.ssh/id_rsa ] &&\
        ssh-keygen -t rsa -P '' -f /home/${USER}/.ssh/id_rsa
    fi
    sshpass -p ${rootpasswd} ssh-copy-id -o StrictHostKeyChecking=no ${USER}@${netnum}.${host}

    if cat /etc/redhat-release &>/dev/null;then
        ssh -o StrictHostKeyChecking=no ${USER}@${netnum}.${host} "yum update -y"
    else
        ssh -o StrictHostKeyChecking=no ${USER}@${netnum}.${host} "apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y"
        [ $? -ne 0 ] && ssh -o StrictHostKeyChecking=no ${USER}@${netnum}.${host} "apt-get -yf install"
    fi
done


# deploy机器下载k8s二进制安装脚本

if [[ ${software_packet} == '' ]];then
    curl -C- -fLO --retry 3 https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
    sed -ri "s+^(K8S_BIN_VER=).*$+\1${k8s_ver}+g" ezdown
    chmod +x ./ezdown
    # 使用工具脚本下载
    ./ezdown -D && ./ezdown -P
else
    tar xvf ${software_packet} -C /etc/
    chmod +x ${pwd}/{ezctl,ezdown}
fi

# 初始化一个名为my的k8s集群配置

CLUSTER_NAME="$clustername"
${pwd}/ezctl new ${CLUSTER_NAME}
if [[ $? -ne 0 ]];then
    echo "cluster name [${CLUSTER_NAME}] was exist in ${pwd}/clusters/${CLUSTER_NAME}."
    exit 1
fi

if [[ ${software_packet} != '' ]];then
    # 设置参数,启用离线安装
    sed -i 's/^INSTALL_SOURCE.*$/INSTALL_SOURCE: "offline"/g' ${pwd}/clusters/${CLUSTER_NAME}/config.yml
fi


# to check ansible service
ansible all -m ping

#---------------------------------------------------------------------------------------------------




#修改二进制安装脚本配置 config.yml

sed -ri "s+^(CLUSTER_NAME:).*$+\1 \"${CLUSTER_NAME}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml

## k8s上日志及容器数据存独立磁盘步骤(参考阿里云的)

[ ! -d /var/lib/container ] && mkdir -p /var/lib/container/{kubelet,docker}

## cat /etc/fstab     
# UUID=105fa8ff-bacd-491f-a6d0-f99865afc3d6 /                       ext4    defaults        1 1
# /dev/vdb /var/lib/container/ ext4 defaults 0 0
# /var/lib/container/kubelet /var/lib/kubelet none defaults,bind 0 0
# /var/lib/container/docker /var/lib/docker none defaults,bind 0 0

## tree -L 1 /var/lib/container
# /var/lib/container
# ├── docker
# ├── kubelet
# └── lost+found

# docker data dir
DOCKER_STORAGE_DIR="/var/lib/container/docker"
sed -ri "s+^(STORAGE_DIR:).*$+STORAGE_DIR: \"${DOCKER_STORAGE_DIR}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
# containerd data dir
CONTAINERD_STORAGE_DIR="/var/lib/container/containerd"
sed -ri "s+^(STORAGE_DIR:).*$+STORAGE_DIR: \"${CONTAINERD_STORAGE_DIR}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
# kubelet logs dir
KUBELET_ROOT_DIR="/var/lib/container/kubelet"
sed -ri "s+^(KUBELET_ROOT_DIR:).*$+KUBELET_ROOT_DIR: \"${KUBELET_ROOT_DIR}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
if [[ $clustername != 'aws' ]]; then
    # docker aliyun repo
    REG_MIRRORS="https://pqbap4ya.mirror.aliyuncs.com"
    sed -ri "s+^REG_MIRRORS:.*$+REG_MIRRORS: \'[\"${REG_MIRRORS}\"]\'+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
fi
# [docker]信任的HTTP仓库
sed -ri "s+127.0.0.1/8+${netnum}.0/24+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
# disable dashboard auto install
sed -ri "s+^(dashboard_install:).*$+\1 \"no\"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml


# 融合配置准备
CLUSEER_WEBSITE="${CLUSTER_NAME}k8s.gtapp.xyz"
lb_num=$(grep -wn '^MASTER_CERT_HOSTS:' ${pwd}/clusters/${CLUSTER_NAME}/config.yml |awk -F: '{print $1}')
lb_num1=$(expr ${lb_num} + 1)
lb_num2=$(expr ${lb_num} + 2)
sed -ri "${lb_num1}s+.*$+  - "${CLUSEER_WEBSITE}"+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml
sed -ri "${lb_num2}s+(.*)$+#\1+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml

# node节点最大pod 数
MAX_PODS="120"
sed -ri "s+^(MAX_PODS:).*$+\1 ${MAX_PODS}+g" ${pwd}/clusters/${CLUSTER_NAME}/config.yml



# 修改二进制安装脚本配置 hosts
# clean old ip
sed -ri '/192.168.1.1/d' ${pwd}/clusters/${CLUSTER_NAME}/hosts
sed -ri '/192.168.1.2/d' ${pwd}/clusters/${CLUSTER_NAME}/hosts
sed -ri '/192.168.1.3/d' ${pwd}/clusters/${CLUSTER_NAME}/hosts
sed -ri '/192.168.1.4/d' ${pwd}/clusters/${CLUSTER_NAME}/hosts

# 输入准备创建ETCD集群的主机位
echo "enter etcd hosts here (example: 203 202 201) ↓"
read -p "" ipnums
for ipnum in `echo ${ipnums}`
do
    echo $netnum.$ipnum
    sed -i "/\[etcd/a $netnum.$ipnum"  ${pwd}/clusters/${CLUSTER_NAME}/hosts
done

# 输入准备创建KUBE-MASTER集群的主机位
echo "enter kube-master hosts here (example: 202 201) ↓"
read -p "" ipnums
for ipnum in `echo ${ipnums}`
do
    echo $netnum.$ipnum
    sed -i "/\[kube_master/a $netnum.$ipnum"  ${pwd}/clusters/${CLUSTER_NAME}/hosts
done

# 输入准备创建KUBE-NODE集群的主机位
echo "enter kube-node hosts here (example: 204 203) ↓"
read -p "" ipnums
for ipnum in `echo ${ipnums}`
do
    echo $netnum.$ipnum
    sed -i "/\[kube_node/a $netnum.$ipnum"  ${pwd}/clusters/${CLUSTER_NAME}/hosts
done

# 配置容器运行时CNI
case ${cni} in
    flannel)
    sed -ri "s+^CLUSTER_NETWORK=.*$+CLUSTER_NETWORK=\"${cni}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/hosts
    ;;
    calico)
    sed -ri "s+^CLUSTER_NETWORK=.*$+CLUSTER_NETWORK=\"${cni}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/hosts
    ;;
    *)
    echo "cni need be flannel or calico."
    exit 11
esac

# 配置K8S的ETCD数据备份的定时任务
if cat /etc/redhat-release &>/dev/null;then
    if ! grep -w '94.backup.yml' /var/spool/cron/root &>/dev/null;then echo "00 00 * * * `which ansible-playbook` ${pwd}/playbooks/94.backup.yml &> /dev/null" >> /var/spool/cron/root;else echo exists ;fi
    chown root.crontab /var/spool/cron/root
    chmod 600 /var/spool/cron/root
else
    if ! grep -w '94.backup.yml' /var/spool/cron/crontabs/root &>/dev/null;then echo "00 00 * * * `which ansible-playbook` ${pwd}/playbooks/94.backup.yml &> /dev/null" >> /var/spool/cron/crontabs/root;else echo exists ;fi
    chown root.crontab /var/spool/cron/crontabs/root
    chmod 600 /var/spool/cron/crontabs/root
fi
rm /var/run/cron.reboot
service crond restart 




#---------------------------------------------------------------------------------------------------
# 准备开始安装了
rm -rf ${pwd}/{dockerfiles,docs,.gitignore,pics,dockerfiles} &&\
find ${pwd}/ -name '*.md'|xargs rm -f
read -p "Enter to continue deploy k8s to all nodes >>>" YesNobbb

# now start deploy k8s cluster 
cd ${pwd}/

# to prepare CA/certs & kubeconfig & other system settings 
${pwd}/ezctl setup ${CLUSTER_NAME} 01
sleep 1
# to setup the etcd cluster
${pwd}/ezctl setup ${CLUSTER_NAME} 02
sleep 1
# to setup the container runtime(docker or containerd)
case ${cri} in
    containerd)
    sed -ri "s+^CONTAINER_RUNTIME=.*$+CONTAINER_RUNTIME=\"${cri}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/hosts
    ${pwd}/ezctl setup ${CLUSTER_NAME} 03
    ;;
    docker)
    sed -ri "s+^CONTAINER_RUNTIME=.*$+CONTAINER_RUNTIME=\"${cri}\"+g" ${pwd}/clusters/${CLUSTER_NAME}/hosts
    ${pwd}/ezctl setup ${CLUSTER_NAME} 03
    ;;
    *)
    echo "cri need be containerd or docker."
    exit 11
esac
sleep 1
# to setup the master nodes
${pwd}/ezctl setup ${CLUSTER_NAME} 04
sleep 1
# to setup the worker nodes
${pwd}/ezctl setup ${CLUSTER_NAME} 05
sleep 1
# to setup the network plugin(flannel、calico...)
${pwd}/ezctl setup ${CLUSTER_NAME} 06
sleep 1
# to setup other useful plugins(metrics-server、coredns...)
${pwd}/ezctl setup ${CLUSTER_NAME} 07
sleep 1
# [可选]对集群所有节点进行操作系统层面的安全加固  https://github.com/dev-sec/ansible-os-hardening
#ansible-playbook roles/os-harden/os-harden.yml
#sleep 1
cd `dirname ${software_packet:-/tmp}`


k8s_bin_path='/opt/kube/bin'


echo "-------------------------  k8s version list  ---------------------------"
${k8s_bin_path}/kubectl version
echo
echo "-------------------------  All Healthy status check  -------------------"
${k8s_bin_path}/kubectl get componentstatus
echo
echo "-------------------------  k8s cluster info list  ----------------------"
${k8s_bin_path}/kubectl cluster-info
echo
echo "-------------------------  k8s all nodes list  -------------------------"
${k8s_bin_path}/kubectl get node -o wide
echo
echo "-------------------------  k8s all-namespaces's pods list   ------------"
${k8s_bin_path}/kubectl get pod --all-namespaces
echo
echo "-------------------------  k8s all-namespaces's service network   ------"
${k8s_bin_path}/kubectl get svc --all-namespaces
echo
echo "-------------------------  k8s welcome for you   -----------------------"
echo

# you can use k alias kubectl to siample
echo "alias k=kubectl && complete -F __start_kubectl k" >> ~/.bashrc

# get dashboard url
${k8s_bin_path}/kubectl cluster-info|grep dashboard|awk '{print $NF}'|tee -a /root/k8s_results

# get login token
${k8s_bin_path}/kubectl -n kube-system describe secret $(${k8s_bin_path}/kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')|grep 'token:'|awk '{print $NF}'|tee -a /root/k8s_results
echo
echo "you can look again dashboard and token info at  >>> /root/k8s_results <<<"
#echo ">>>>>>>>>>>>>>>>> You can excute command [ source ~/.bashrc ] <<<<<<<<<<<<<<<<<<<<"
echo ">>>>>>>>>>>>>>>>> You need to excute command [ reboot ] to restart all nodes <<<<<<<<<<<<<<<<<<<<"
rm -f $0
[ -f ${software_packet} ] && rm -f ${software_packet}
#rm -f ${pwd}/roles/deploy/templates/${USER_NAME}-csr.json.j2
#sed -ri "s+${USER_NAME}+admin+g" ${pwd}/roles/prepare/tasks/main.yml

如下是开始安装执行脚本


# 开始在线安装(这里选择容器运行时是docker,CNI为calico,K8S集群名称为test)
bash k8s_install_new.sh bogedevops 10.0.1 201\ 202\ 203\ 204 docker calico test

# 需要注意的在线安装因为会从github及dockerhub上下载文件及镜像,有时候访问这些国外网络会非常慢,这里我也会大家准备好了完整离线安装包,下载地址如下,和上面的安装脚本放在同一目录下,再执行上面的安装命令即可
# 此离线安装包里面的k8s版本为v1.20.2
https://cloud.189.cn/t/3YBV7jzQZnAb (访问码:0xde)

# 脚本基本是自动化的,除了下面几处提示按要求复制粘贴下,再回车即可

# 输入准备创建ETCD集群的主机位,复制  203 202 201 粘贴并回车
echo "enter etcd hosts here (example: 203 202 201) ↓"

# 输入准备创建KUBE-MASTER集群的主机位,复制  202 201 粘贴并回车
echo "enter kube-master hosts here (example: 202 201) ↓"

# 输入准备创建KUBE-NODE集群的主机位,复制  204 203 粘贴并回车
echo "enter kube-node hosts here (example: 204 203) ↓"

# 这里会提示你是否继续安装,没问题的话直接回车即可
Enter to continue deploy k8s to all nodes >>>

# 安装完成后重新加载下环境变量以实现kubectl命令补齐
. ~/.bashrc 

第4关 K8s最得意的小弟Docker

知己知彼方能百战百胜,无论是游戏还是技术都是同一个道理,docker只是容器化引擎中的一种,但由于它入行较早,深得K8s的青睐,所以现在大家提到容器技术就想到docker,docker俨然成为了容器技术的代名词了,那我们该如何击败这个docker呢,下面我们仔细分析下docker它的各个属性和技能吧。

Docker是dotCloud公司用Google公司推出的Go语言开发实现,基于Linux内核的namespace、cgroup,以及AUFS类的Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。

下面的图片比较了 Docker 和传统虚拟化方式的不同之处。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

为什么要使用 Docker?

  • 更高效的利用系统资源
  • 更快速的启动时间
  • 一致的运行环境
  • 持续交付和部署
  • 更轻松的迁移
  • 更轻松的维护和扩展

对比传统虚拟机总结

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

docker的三板斧分别是:

  • 镜像(Image)
  • 容器(Container)
  • 仓库(Repository)

docker的必杀技是:

  • Dockerfile

下面以生产中实际的案例来让大家熟悉docker的整个生命周期,确保将其一击即溃。

python

FROM python:3.7-slim-stretch
MAINTAINER boge 

WORKDIR /app

COPY requirements.txt .

RUN  sed -i 's/deb.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
  && sed -i 's/security.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
  && apt-get update -y \
  && apt-get install -y wget gcc libsm6 libxext6 libglib2.0-0 libxrender1 git vim \
  && apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt \
    && rm requirements.txt

COPY . .

EXPOSE 5000
HEALTHCHECK CMD curl --fail http://localhost:5000 || exit 1

ENTRYPOINT ["gunicorn", "app:app", "-c", "gunicorn_config.py"]

golang

# stage 1: build src code to binary
FROM golang:1.13-alpine3.10 as builder
MAINTAINER boge 

ENV GOPROXY https://goproxy.cn

# ENV GO111MODULE on

COPY *.go /app/

RUN cd /app && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o hellogo .

# stage 2: use alpine as base image
FROM alpine:3.10

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    apk update && \
    apk --no-cache add tzdata ca-certificates && \
    cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    # apk del tzdata && \
    rm -rf /var/cache/apk/*


COPY --from=builder /app/hellogo /hellogo

CMD ["/hellogo"] 

nodejs

FROM node:12.6.0-alpine
MAINTAINER boge 

WORKDIR /app
COPY package.json .

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    apk update && \
    yarn  config set registry https://registry.npm.taobao.org && \
    yarn install

RUN yarn build

COPY . .

EXPOSE 6868

ENTRYPOINT ["yarn", "start"]

java

FROM maven:3.6.3-adoptopenjdk-8 as target

ENV MAVEN_HOME /usr/share/maven
ENV PATH $MAVEN_HOME/bin:$PATH
COPY settings.xml /usr/share/maven/conf/
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline  # use docker cache
COPY src/ /build/src/
RUN mvn clean package -Dmaven.test.skip=true


FROM java:8
WORKDIR /app
RUN  rm /etc/localtime && cp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime
COPY --from=target /build/target/*.jar  /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Xmx768m","-Xms256m","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]

docker的整个生命周期展示

# 登陆docker镜像仓库
docker login "仓库地址" -u "仓库用户名" -p "仓库密码"
# 从仓库下载镜像
docker pull "仓库地址"/"仓库命名空间"/"镜像名称":latest || true
# 基于Dockerfile构建本地镜像
docker build --network host --build-arg PYPI_IP="xx.xx.xx.xx" --cache-from "仓库地址"/"仓库命名空间"/"镜像名称":latest --tag "仓库地址"/"仓库命名空间"/"镜像名称":"镜像版本号" --tag "仓库地址"/"仓库命名空间"/"镜像名称":latest .
# 将构建好的本地镜像推到远端镜像仓库里面
docker push "仓库地址"/"仓库命名空间"/"镜像名称":"镜像版本号"
docker push "仓库地址"/"仓库命名空间"/"镜像名称":latest
# 基于redis的镜像运行一个docker实例
docker run --name myredis --net host -d redis:6.0.2-alpine3.11 redis-server --requirepass boGe666

开始实战,迎击第4关的小BOOS战,获取属于我们的经验值

我这里将上面的flask和golang项目上传到了网盘,地址如下:

https://cloud.189.cn/t/M36fYrIrEbui (访问码:hy47)

大家下载解压后,会得到2个目录,一个python,一个golang

# 解压
unzip docker-file.zip

# 先打包python项目的镜像并运行测试
cd python
docker build -t python/flask:v0.0.1 .
docker run -d -p 80:5000 python/flask:v0.0.1

# 再打包golang项目的镜像并运行测试
docker build -t boge/golang:v0.0.1 .
docker run -d -p80:3000 boge/golang:v0.0.1

第5关 K8s攻克作战攻略之一

第3关我们以二进制的形式部署好了一套K8S集群,现在我们就来会会K8S吧

K8s的API对象(所有怪物角色列表)

看了上面这一堆知识点,大家是不是有点头晕了? 别担心,上述这些小怪在后面的过关流程中均会一一遇到,并且我会也教会大家怎么去战胜它们,Let’ Go!

OK,此关卡较长,这节课我们先会会Namespace和Pod这两个小怪

Namespace

namespace命令空间,后面简称ns。在K8s上面,大部分资源都受ns的限制,来做资源的隔离,少部分如pv,clusterRole等不受ns控制,这个后面会讲到。

# 查看目前集群上有哪些ns
# kubectl get ns
NAME              STATUS        AGE
default           Active        5d3h
kube-node-lease   Active        5d3h
kube-public       Active        5d3h
kube-system       Active        5d3h

# 通过kubectl 接上 -n namespaceName 来查看对应ns上面的资源信息
# kubectl -n kube-system get pod
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-7fdc86d8ff-2mcm9   1/1     Running   1          29h
calico-node-dlt57                          1/1     Running   1          29h
calico-node-tvzqj                          1/1     Running   1          29h
calico-node-vh6sk                          1/1     Running   1          29h
calico-node-wpsfh                          1/1     Running   1          29h
coredns-d9b6857b5-tt7j2                    1/1     Running   1          29h
metrics-server-869ffc99cd-n2dc4            1/1     Running   2          29h
nfs-provisioner-01-77549d5487-dbmv5        1/1     Running   2          29h

# kubectl -n kube-system top pod  #显示pod资源使用情况

# 我们通过不接-n 的情况下,都是在默认命令空间default下进行操作,在生产中,通过测试一些资源就在这里进行
[root@node-1 ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-867c95f465-njv78   1/1     Running   0          12m
[root@node-1 ~]# kubectl -n default get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-867c95f465-njv78   1/1     Running   0          12m

# 创建也很简单
[root@node-1 ~]# kubectl create ns test
namespace/test created
[root@node-1 ~]# kubectl get ns|grep test
test  

# 删除ns
# kubectl delete ns test 
namespace "test" deleted

生产中的小技巧:k8s删除namespaces状态一直为terminating问题处理

# kubectl get ns
NAME              STATUS        AGE
default           Active        5d4h
ingress-nginx     Active        30h
kube-node-lease   Active        5d4h
kube-public       Active        5d4h
kube-system       Active        5d4h
kubevirt          Terminating   2d2h   # <------ here

1、新开一个窗口运行命令  kubectl proxy
> 此命令启动了一个代理服务来接收来自你本机的HTTP连接并转发至API服务器,同时处理身份认证

2、新开一个终端窗口,将下面shell脚本整理到文本内`1.sh`并执行,$1参数即为删除不了的ns名称
#------------------------------------------------------------------------------------
#!/bin/bash

set -eo pipefail

die() { echo "$*" 1>&2 ; exit 1; }

need() {
        which "$1" &>/dev/null || die "Binary '$1' is missing but required"
}

# checking pre-reqs

need "jq"
need "curl"
need "kubectl"

PROJECT="$1"
shift

test -n "$PROJECT" || die "Missing arguments: kill-ns "

kubectl proxy &>/dev/null &
PROXY_PID=$!
killproxy () {
        kill $PROXY_PID
}
trap killproxy EXIT

sleep 1 # give the proxy a second

kubectl get namespace "$PROJECT" -o json | jq 'del(.spec.finalizers[] | select("kubernetes"))' | curl -s -k -H "Content-Type: application/json" -X PUT -o /dev/null --data-binary @- http://localhost:8001/api/v1/namespaces/$PROJECT/finalize && echo "Killed namespace: $PROJECT"
#------------------------------------------------------------------------------------

3. 执行脚本删除
# bash 1.sh kubevirt
Killed namespace: kubevirt
1.sh: line 23: kill: (9098) - No such process

5、查看结果
# kubectl get ns    
NAME              STATUS   AGE
default           Active   5d4h
ingress-nginx     Active   30h
kube-node-lease   Active   5d4h
kube-public       Active   5d4h
kube-system       Active   5d4h

Pod

kubectl作为管理K8s的重要cli命令行工具,运维人员必须掌握它,但里面这么多的子命令,记不住怎么办?这里就以创建pod举例

擅用-h 帮助参数

# 在新版本的K8s中,明确了相关命令就是用来创建对应资源的,不再像老版本那样混合使用,这个不是重点,创建pod,我们用kubectl run -h,来查看命令帮助,是不是豁然开朗
# kubectl run -h
Create and run a particular image in a pod.

Examples:
  # Start a nginx pod.
  kubectl run nginx --image=nginx
  ......

# 我们就用示例给出的第一个示例,来创建一个nginx的pod
# kubectl run nginx --image=nginx
pod/nginx created

# 等待镜像下载完成后,pod就会正常running了(这里介绍两个实用参数 -w代表持久监听当前namespace下的指定资源的变化;-o wide代表列出更为详细的信息,比如这里pod运行的node节点显示)
# 注: READY下面的含义是后面数字1代表这个pod里面期望的容器数量,前面的数字1代表服务正常运行就绪的容器数量
# kubectl  get pod -w -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
nginx                   1/1     Running   0          2m35s   172.20.139.67   10.0.1.203              

# 我们来请求下这个pod的IP
# curl 172.20.139.67



Welcome to nginx!
......

# 我们进到这个pod服务内,修改下页面信息看看,这里会学到exec子命令,-it代表保持tty连接,不会一连上pod就断开了
# ************************************************************
# kubectl -it exec nginx -- sh
# echo 'hello, world!' > /usr/share/nginx/html/index.html
# exit

# curl 172.20.139.67
hello, world!


# 我们来详细分析的这个pod启动的整个流程,这里会用到kubectl的子命令 describe,它是用来描述后面所接资源的详细信息的,划重点,这个命令对于我们生产中排查K8s的问题尤其重要
# kubectl  describe pod nginx   # 这里显示内容较多,目前我只把当前关键的信息列出来

Name:         nginx
Namespace:    default
Priority:     0
Node:         10.0.1.203/10.0.1.203
Start Time:   Tue, 24 Nov 2020 14:23:56 +0800
Labels:       run=nginx
Annotations:  
Status:       Running
IP:           172.20.139.67
IPs:
  IP:  172.20.139.67
Containers:
  nginx:
    Container ID:   docker://2578019be269d7b1ad02ab4dd0a8b883e79fc491ae9c5db6164120f3e1dde8c7
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:c3a1592d2b6d275bef4087573355827b200b00ffc2d9849890a4f3aa2128c4ae
    Port:           
    Host Port:      
    State:          Running
......中间内容省略
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  5m41s  default-scheduler  Successfully assigned default/nginx to 10.0.1.203
  Normal  Pulling    5m40s  kubelet            Pulling image "nginx"
  Normal  Pulled     5m25s  kubelet            Successfully pulled image "nginx"
  Normal  Created    5m25s  kubelet            Created container nginx
  Normal  Started    5m25s  kubelet            Started container nginx
  
 # 重点分析下最后面的Events事件链
1. kubectl 发送部署pod的请求到 API Server
2. API Server 通知 Controller Manager 创建一个 pod 资源
3. Scheduler 执行调度任务,Events的第一条打印信息就明确显示了这个pod被调度到10.0.1.203这个node节点上运行,接着开始拉取相应容器镜像,拉取完成后开始创建nginx服务,至到最后服务创建完成,在有时候服务报错的时候,这里也会显示相应详细的报错信息

但我们在生产中是不建议直接用来创建pod,先直接演示下:

# 我们删除掉这个nginx的pod
# kubectl delete pod nginx
pod "nginx" deleted

# kubectl get pod
现在已经看不到这个pod了,假设这里是我们运行的一个服务,而恰好运行这个pod的这台node当机了,那么这个服务就没了,它不会自动飘移到其他node上去,也就发挥不了K8s最重要的保持期待的服务特性了。

小技巧之列出镜像的相关tag,方便进行镜像tag版本选择:

这个脚本是从二进制安装K8S那个项目里面提取的一个小脚本,因为用来查docker镜像版本很方便,所以在这里分享给大家

# cat /opt/kube/bin/docker-tag        
#!/bin/bash
#

MTAG=$2
CONTAIN=$3

function usage() {
cat << HELP

docker-tag  --  list all tags for a Docker image on a remote registry

EXAMPLe:
    - list all tags for nginx:
       docker-tag tags nginx

    - list all nginx tags containing alpine:
       docker-tag tags nginx alpine

HELP
}

if [ $# -lt 1 ]; then
        usage
        exit 2
fi

function tags() {
    TAGS=$(curl -ksL https://registry.hub.docker.com/v1/repositories/${MTAG}/tags | sed -e 's/[][]//g' -e 's/"//g' -e 's/ //g' | tr '}' '\n'  | awk -e: '{print $3}')
    if [ "${CONTAIN}" != "" ]; then
        echo -e $(echo "${TAGS}" | grep "${CONTAIN}") | tr ' ' '\n'
    else
        echo "${TAGS}"
    fi
}


case $1 in
    tags)
        tags
        ;;
    *)
        usage
        ;;
esac

显示结果如下:

# docker-tag tags nginx        
latest
1
1-alpine
1-alpine-perl
1-perl
1.10
1.10-alpine

pod小怪战斗(作业)

# 试着创建一个redis服务的pod,并且使用exec进入这个pod,通过客户端命令redis-cli连接到redis-server ,插入一个key a ,value 为666,最后删除这个redis的pod
root@redis:/data# redis-cli 
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> set a 666
OK
127.0.0.1:6379> get a
"666"

第5关 K8s攻克作战攻略之二-Deployment

Deployment

这节课大家跟随博哥爱运维来会会deployment这个怪物

K8s会通过各种Controller来管理Pod的生命周期,为了满足不同的业务场景,K8s开发了Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job、cronJob等多种Controller ,这里我们首先来学习下最常用的Deployment,这是我们生产中用的最多的一个controller,适合用来发布无状态应用.

我们先来运行一个Deployment实例:

# 创建一个deployment,引用nginx的服务镜像,这里的副本数量默认是1,nginx容器镜像用的是latest
# 在K8s新版本开始,对服务api进行了比较大的梳理,明确了各个api的具体职责,而不像以前旧版本那样混为一谈
# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created

# 查看创建结果
# kubectl  get deployments.apps 
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   0/1     1            0           6s

# kubectl  get rs   # <-- 看下自动关联创建的副本集replicaset
NAME              DESIRED   CURRENT   READY   AGE
nginx-f89759699   1         1         0       10s

# kubectl get pod   # <-- 查看生成的pod,注意镜像下载需要一定时间,耐心等待,注意观察pod名称的f89759699,是不是和上面rs的一样,对了,因为这里的pod就是由上面的rs创建出来,为什么要设置这么一个环节呢,后面会以实例来演示
NAME                    READY   STATUS              RESTARTS   AGE
nginx-f89759699-26fzd   0/1     ContainerCreating   0          13s

# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-26fzd   1/1     Running   0          98s


# 扩容pod的数量
# kubectl scale deployment nginx --replicas=2
deployment.apps/nginx scaled

# 查看扩容后的pod结果
# kubectl get pod
NAME                    READY   STATUS              RESTARTS   AGE
nginx-f89759699-26fzd   1/1     Running             0          112s
nginx-f89759699-9s4dw   0/1     ContainerCreating   0          2s

# 具体看下pod是不是分散运行在不同的node上呢
# kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
nginx-f89759699-26fzd   1/1     Running   0          45m   172.20.0.16   10.0.1.202              
nginx-f89759699-9s4dw   1/1     Running   0          43m   172.20.1.14   10.0.1.201              


# 接下来替换下这个deployment里面nginx的镜像版本,来讲解下为什么需要rs副本集呢,这个很重要哦
# 我们先看看目前nginx是哪个版本,随便输入一个错误的uri,页面就会打印出nginx的版本号了
curl 10.68.86.85/1

404 Not Found

404 Not Found


nginx/1.19.4
# 根据输出可以看到版本号是nginx/1.19.4,这里利用上面提到的命令docker-tag来看下nginx有哪些其他的版本,然后我在里面挑选了1.9.9这个tag号 # 注意命令最后面的 `--record` 参数,这个在生产中作为资源创建更新用来回滚的重要标记,强烈建议在生产中操作时都加上这个参数 # kubectl set image deployment/nginx nginx=nginx:1.9.9 --record deployment.apps/nginx image updated # 观察下pod的信息,可以看到旧nginx的2个pod逐渐被新的pod一个一个的替换掉 # kubectl get pod -w NAME READY STATUS RESTARTS AGE nginx-89fc8d79d-4z876 1/1 Running 0 41s nginx-89fc8d79d-jd78f 0/1 ContainerCreating 0 3s nginx-f89759699-9cx7l 1/1 Running 0 4h53m # 我们再看下nginx的rs,可以看到现在有两个了 # kubectl get rs NAME DESIRED CURRENT READY AGE nginx-89fc8d79d 2 2 2 9m6s nginx-f89759699 0 0 0 6h15m # 看下现在nginx的描述信息,我们来详细分析下这个过程 # kubectl describe deployment nginx Name: nginx Namespace: default CreationTimestamp: Tue, 24 Nov 2020 09:40:54 +0800 Labels: app=nginx ...... RollingUpdateStrategy: 25% max unavailable, 25% max surge # 注意这里,这个就是用来控制rs新旧版本迭代更新的一个频率,滚动更新的副本总数最大值(以2的基数为例):2+2*25%=2.5 -- > 3,可用副本数最大值(默认值两个都是25%):2-2*25%=1.5 --> 2 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 21m deployment-controller Scaled up replica set nginx-89fc8d79d to 1 # 启动1个新版本的pod Normal ScalingReplicaSet 20m deployment-controller Scaled down replica set nginx-f89759699 to 1 # 上面完成就释放掉一个旧版本的 Normal ScalingReplicaSet 20m deployment-controller Scaled up replica set nginx-89fc8d79d to 2 # 然后再启动1个新版本的pod Normal ScalingReplicaSet 20m deployment-controller Scaled down replica set nginx-f89759699 to 0 # 释放掉最后1个旧的pod # 回滚 # 还记得我们上面提到的 --record 参数嘛,这里它就会发挥很重要的作用了 # 这里还以nginx服务为例,先看下当前nginx的版本号 # curl 10.68.18.121/1 404 Not Found

404 Not Found


nginx/1.9.9
# 升级nginx的版本 # kubectl set image deployments/nginx nginx=nginx:1.19.5 --record # 已经升级完成 # curl 10.68.18.121/1 404 Not Found

404 Not Found


nginx/1.19.5
# 这里假设是我们在发版服务的新版本,结果线上反馈版本有问题,需要马上回滚,看看在K8s上怎么操作吧 # 首先通过命令查看当前历史版本情况,只有接了`--record`参数的命令操作才会有详细的记录,这就是为什么在生产中操作一定得加上的原因了 # kubectl rollout history deployment nginx deployment.apps/nginx REVISION CHANGE-CAUSE 1 2 kubectl set image deployments/nginx nginx=nginx:1.9.9 --record=true 3 kubectl set image deployments/nginx nginx=nginx:1.19.5 --record=true # 根据历史发布版本前面的阿拉伯数字序号来选择回滚版本,这里我们回到上个版本号,也就是选择2 ,执行命令如下: # kubectl rollout undo deployment nginx --to-revision=2 deployment.apps/nginx rolled back # 等一会pod更新完成后,看下结果已经回滚完成了,怎么样,在K8s操作就是这么简单: # curl 10.68.18.121/1 404 Not Found

404 Not Found


nginx/1.9.9
# 可以看到现在最新版本号是4了,具体版本看操作的命令显示是1.9.9 ,并且先前回滚过的版本号2已经没有了,因为它已经变成4了 # kubectl rollout history deployment nginx deployment.apps/nginx REVISION CHANGE-CAUSE 1 3 kubectl set image deployments/nginx nginx=nginx:1.19.5 --record=true 4 kubectl set image deployments/nginx nginx=nginx:1.9.9 --record=true

Deployment很重要,我们这里再来回顾下整个部署过程,加深理解

10.0.1.201 10.0.1.202

  1. kubectl 发送部署请求到 API Server
  2. API Server 通知 Controller Manager 创建一个 deployment 资源(scale扩容)
  3. Scheduler 执行调度任务,将两个副本 Pod 分发到 10.0.1.201 和 10.0.1.202
  4. 10.0.1.201 和 10.0.1.202 上的 kubelet在各自的节点上创建并运行 Pod
  5. 升级deployment的nginx服务镜像

这里补充一下:

这些应用的配置和当前服务的状态信息都是保存在ETCD中,执行kubectl get pod等操作时API Server会从ETCD中读取这些数据

calico会为每个pod分配一个ip,但要注意这个ip不是固定的,它会随着pod的重启而发生变化

附:Node管理

禁止pod调度到该节点上

kubectl cordon

驱逐该节点上的所有pod kubectl drain 该命令会删除该节点上的所有Pod(DaemonSet除外),在其他node上重新启动它们,通常该节点需要维护时使用该命令。直接使用该命令会自动调用kubectl cordon 命令。当该节点维护完成,启动了kubelet后,再使用kubectl uncordon 即可将该节点添加到kubernetes集群中。

上面我们是用命令行来创建的deployment,但在生产中,很多时候,我们是直接写好yaml配置文件,再通过kubectl apply -f xxx.yaml来创建这个服务,我们现在用yaml配置文件的方式实现上面deployment服务的创建

需要注意的是,yaml文件格式缩进和python语法类似,对于缩进格式要求很严格,任何一处错误,都会造成无法创建,这里教大家一招实用的技巧来生成规范的yaml配置

# 这条命令是不是很眼熟,对了,这就是上面创建deployment的命令,我们在后面加上`--dry-run -o yaml`,--dry-run代表这条命令不会实际在K8s执行,-o yaml是会将试运行结果以yaml的格式打印出来,这样我们就能轻松获得yaml配置了

# kubectl create deployment nginx --image=nginx --dry-run -o yaml       
apiVersion: apps/v1     # <---  apiVersion 是当前配置格式的版本
kind: Deployment     #<--- kind 是要创建的资源类型,这里是 Deployment
metadata:        #<--- metadata 是该资源的元数据,name 是必需的元数据项
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:        #<---    spec 部分是该 Deployment 的规格说明
  replicas: 1        #<---  replicas 指明副本数量,默认为 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:        #<---   template 定义 Pod 的模板,这是配置文件的重要部分
    metadata:        #<---     metadata 定义 Pod 的元数据,至少要定义一个 label。label 的 key 和 value 可以任意指定
      creationTimestamp: null
      labels:
        app: nginx
    spec:           #<---  spec 描述 Pod 的规格,此部分定义 Pod 中每一个容器的属性,name 和 image 是必需的
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

我们这里用这个yaml文件来创建nginx的deployment试试,我们先删除掉先用命令行创建的nginx

# 在K8s上命令行删除一个资源直接用delete参数
# kubectl delete deployment nginx
deployment.apps "nginx" deleted

# 可以看到关联的rs副本集也被自动清空了
# kubectl  get rs
No resources found in default namespace.

# 相关的pod也没了
# kubectl get pod 
No resources found in default namespace.

生成nginx.yaml文件

# kubectl create deployment nginx --image=nginx --dry-run -o yaml > nginx.yaml
我们注意到执行上面命令时会有一条告警提示... --dry-run is deprecated and can be replaced with --dry-run=client.  ,虽然并不影响我们生成正常的yaml配置,但如果看着不爽可以按命令提示将--dry-run换成--dry-run=client
# 接着我们vim nginx.yaml,将replicas: 1的数量改成replicas: 2

# 开始创建,我们后面这类基于yaml文件来创建资源的命令统一都用apply了
# kubectl  apply -f nginx.yaml 
deployment.apps/nginx created

# 查看创建的资源,这个有个小技巧,同时查看多个资源可以用,分隔,这样一条命令就可以查看多个资源了
# kubectl get deployment,rs,pod
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   2/2     2            2           116s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-f89759699   2         2         2       116s

NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-f89759699-bzwd2   1/1     Running   0          116s
pod/nginx-f89759699-qlc8q   1/1     Running   0          116s

# 删除通过kubectl apply -f nginx.yaml创建的资源
kubectl delete -f nginx.yaml

基于这两种资源创建的方式作个总结:

基于命令的方式:
1.简单直观快捷,上手快。
2.适合临时测试或实验。

基于配置文件的方式:
1.配置文件描述了 What,即应用最终要达到的状态。
2.配置文件提供了创建资源的模板,能够重复部署。
3.可以像管理代码一样管理部署。
4.适合正式的、跨环境的、规模化部署。
5.这种方式要求熟悉配置文件的语法,有一定难度。

deployment小怪战斗(作业)

试着用命令行和yaml配置这两种方式,来创建redis的deployment服务,同时可以将pod后面的作业再复习下

第5关 K8s攻克作战攻略之三-服务pod的健康检测

大家好,我是博哥爱运维,这节课内容给大家讲解下在K8S上,我们如果对我们的业务服务进行健康检测。

Health Check

这里我们再进一步,来聊聊K8s上面服务的健康检测特性。在K8s上,强大的自愈能力是这个容器编排引擎的非常重要的一个特性,自愈的默认实现方式是通过自动重启发生故障的容器,使之恢复正常。除此之外,我们还可以利用Liveness 和 Readiness检测机制来设置更为精细的健康检测指标,从而实现如下的需求:

  • 零停机部署
  • 避免部署无效的服务镜像
  • 更加安全地滚动升级

下面我们先来实践学习下K8s的Healthz Check功能,我们先来学习下K8s默认的健康检测机制

每个容器启动时都会执行一个进程,此进程是由Dockerfile的CMD 或 ENTRYPOINT来指定,当容器内进程退出时返回状态码为非零,则会认为容器发生了故障,K8s就会根据restartPolicy来重启这个容器,以达到自愈的效果

下面我们来动手实践下,模拟一个容器发生故障时的场景 :

# 先来生成一个pod的yaml配置文件,并对其进行相应修改
# kubectl run  busybox --image=busybox --dry-run=client -o yaml > testHealthz.yaml
# vim testHealthz.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: busybox
  name: busybox
spec:
  containers:
  - image: busybox
    name: busybox
    resources: {}
    args:
    - /bin/sh
    - -c
    - sleep 10; exit 1       # 并添加pod运行指定脚本命令,模拟容器启动10秒后发生故障,退出状态码为1
  dnsPolicy: ClusterFirst
  restartPolicy: OnFailure # 将默认的Always修改为OnFailure
status: {}
重启策略 说明
Always 当容器失效时,由kubelet自动重启该容器
OnFailure 当容器终止运行且退出码不为0时,由kubelet自动重启该容器
Never 不论容器运行状态如何,kubelet都不会重启该容器

执行配置创建pod

# kubectl apply -f testHealthz.yaml 
pod/busybox created

# 观察几分钟,利用-w 参数来持续监听pod的状态变化
# kubectl  get pod -w
NAME                     READY   STATUS              RESTARTS   AGE
busybox                  0/1     ContainerCreating   0          4s
busybox                  1/1     Running             0          6s
busybox                  0/1     Error               0          16s
busybox                  1/1     Running             1          22s
busybox                  0/1     Error               1          34s
busybox                  0/1     CrashLoopBackOff    1          47s
busybox                  1/1     Running             2          63s
busybox                  0/1     Error               2          73s
busybox                  0/1     CrashLoopBackOff    2          86s
busybox                  1/1     Running             3          109s
busybox                  0/1     Error               3          2m
busybox                  0/1     CrashLoopBackOff    3          2m15s
busybox                  1/1     Running             4          3m2s
busybox                  0/
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章