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

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

  • Namespace – 命令空间实现同一集群上的资源隔离
  • Pod – K8s的最小运行单元
  • ReplicaSet – 实现pod平滑迭代更新及回滚用,这个不需要我们实际操作
  • Deployment – 用来发布无状态应用
  • Health Check – Readiness/Liveness/maxSurge/maxUnavailable 服务健康状态检测
  • Service, Endpoint – 实现同一lables下的多个pod流量负载均衡
  • Labels – 标签,服务间选择访问的重要依据
  • Ingress – K8s的流量入口
  • DaemonSet – 用来发布守护应用,例如我们部署的CNI插件
  • HPA – Horizontal Pod Autoscaling 自动水平伸缩
  • Volume – 存储卷
  • Pv, pvc, StorageClass – 持久化存储,持久化存储 声明,动态存储pv
  • StatefulSet – 用来发布有状态应用
  • Job, CronJob – 一次性任务及定时任务
  • Configmap, serect – 服务配置及服务加密配置
  • Kube-proxy – 提供service服务流量转发的功能支持,这个不需要我们实际操作
  • RBAC, serviceAccount, role, rolebindings, clusterrole, clusterrolebindings – 基于角色的访问控制
  • Events – K8s事件流,可以用来监控相关事件用,这个不需要我们实际操作

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

# 我们通过不接-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 <namespace>"

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

开篇先来个加人头秘籍(上上下下左右左右BABA,知道这个游戏的朋友请举个手^0^)

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   <none>           <none>

# 我们来请求下这个pod的IP
# curl 172.20.139.67
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
......

# 我们进到这个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:  <none>
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:           <none>
    Host Port:      <none>
    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"
文档更新时间: 2021-07-28 16:12   作者:李延召