# 客户端

# kubectl

  • kubectl 是 k8s 官方发行的一个命令行工具,作为客户端访问 kube-apiserver ,从而管理已部署的 k8s 集群。

# 安装

  • 下载二进制文件:
    wget https://dl.k8s.io/release/v1.23.1/bin/linux/amd64/kubectl -O /usr/bin/kubectl
    chmod +x /usr/bin/kubectl
    kubectl completion bash > /etc/bash_completion.d/kubectl  # 启用 kubectl 命令补全,保存为 bash_completion 脚本
    
  • kubectl 命令通过访问 kube-apiserver 来控制 k8s 集群,此时需要读取一种配置文件,称为 kubeconfig 。
    • kubeconfig 配置了要连接的 kube-apiserver 地址,以及账号。
    • kubectl 默认从 ~/.kube/config 路径读取 kubeconfig ,也可以在执行命令时加上 --kubeconfig <path> 参数,或声明环境变量 export KUBECONFIG=<path>

# 命令

kubectl
        --kubeconfig <path>

        # 查看集群
        version             # 显示 client、server 的版本
        config              # 访问 kubeconfig
            view            # 显示 kubeconfig 的内容
              --raw         # 是否显示完整内容,默认省略 token

        # 修改资源
        create                      # 创建资源
            -f <file>               # 指定一个 YAML 配置文件。不支持指定多个文件,支持以 URL 的形式指定配置文件
            -f <dir>                # 指定一个目录,读取其下所有配置文件
              -R                    # 递归处理目录
            -k <dir>                # 指定一个 kustomization 目录
        edit <resource> <name>      # 修改资源的 YAML 配置文件
        replace -f <file>           # 替换资源的配置文件。如果该资源不存在则报错。如果只是更改无序字段的顺序,则不会更新配置文件
            --force                 # 先删除旧资源,再创建
        apply -f <file>             # 更新资源的配置文件。如果该资源不存在则自动创建,如果该资源没有变化则显示 unchanged

        patch -p '{"spec":{"unschedulable":true}}'  # 更新资源的配置文件中的指定字段,而不是修改整个配置文件
        label <resource> <name>
              <key>=<value>...      # 给资源添加标签
                --overwrite         # 如果该标签已存在,则覆盖它的值。默认不会覆盖,而是报错
              <key>-                # 删除标签
        delete                      # 删除资源
            pod <name>...           # 删除指定名称的 pod
            deployment <name>...    # 删除指定名称的 deployment
            -f <file>               # 删除配置文件中指定的资源
            --force                 # 立即从 etcd 删除资源,同时命令 kubelet 终止相应的 Pod ,依然会等待一小段宽限期
            --grace-period=30       # 覆盖 Pod 已配置的宽限期
            --ignore-not-found      # 如果要删除的资源不存在,则不报错。默认会报错
            --wait=true             # 默认为 true ,会等待资源被成功删除,才结束 kubelet delete 命令。比如删除 Pod 时需要等待宽限期
            --timeout=0s            # --wait 的超时时间

        # 查看资源
        describe <resource> [name]  # 查看指定资源的信息,包括 spec、status、event 等
                node [name]         # 查看指定 node 上部署了哪些 Pod ,以及每个 Pod 的 CPU 、内存使用率
        get <resource> [name]...    # 查看资源的信息。不指定 name 则显示这种资源的所有实例
            --kubeconfig ~/.kube/config # 指定 kubeconfig 的文件路径
            -n default              # --namespace ,指定命名空间,只查看该命名空间中的资源
            -A                      # --all-namespaces ,查看所有命名空间
            -l 'k1=v1, k2 notin (v1,v2)'            # --selector ,标签选择器
            --field-selector status.phase!=Running  # 字段选择器
            -w                      # --watch ,先显示当前 get 的结果,然后保持执行命令,当有资源变化时就增加显示
            --watch-only            # 不显示当前 get 的结果,直接 watch
            -o wide                 # --output ,输出格式。默认显示列表格式的简介,wide 是显示更多列
            -o name                 # 只显示名称
            -o json                 # 显示 JSON 格式
            -o yaml                 # 显示 YAML 格式
            -o template --template={{.spec.replicas}} # 按自定义的 Golang 模板显示

        # 管理 Node
        cordon      <node>          # 暂停调度一个节点。这会给该节点添加 node.kubernetes.io/unschedulable 污点,避免调度新 Pod ,但不影响已调度的 Pod
        uncordon    <node>          # 恢复调度一个节点
        drain       <node>          # 清空节点上的 Pod 。这会先 cordon 该节点,然后驱逐已调度的所有 Pod 。驱逐完之后,该命令才退出
            --delete-emptydir-data  # 如果有 Pod 挂载了 emptyDir 数据卷,默认会导致 drain 命令中断,除非加上该选项
            --force                 # 如果有 Pod 不受 controller 管理,默认会导致 drain 命令中断,除非加上该选项
            --ignore-daemonsets     # 如果有 Daemonset 类型的 Pod ,默认会导致 drain 命令中断,除非加上该选项。因为 Daemonset 类型的 Pod 会容忍 node.kubernetes.io/unschedulable 污点,依然会调度到该节点
        taint node  <node>          # 设置节点的污点
                        dedicated=db:NoSchedule # 设置一个键值对 dedicated=special 作为污点,效果为 NoSchedule
                        dedicated-              # 删除指定 key 的所有污点

        # 管理 pod
        expose                      # 创建 service ,暴露端口
        exec <pod> -- <command>     # 在 pod 中执行命令,采用容器内的默认用户(不支持主动选用 root 用户)。注意在 command 之前要加上分隔符 --
            -c <name>               # --container ,选择 pod 中的某个容器。默认选择第一个容器
            -it                     # 进入容器内终端
        rollout [command] <resource> [name]...  # 更新部署应用,仅限 daemonset、deployment、statefulset 类型,如果省略 name 则选择所有应用
            history                 # 显示更新部署的历史版本,默认只记录最近 10 个
            pause                   # 暂停更新
            resume                  # 继续更新
            restart                 # 根据 spec.strategy 重启应用(在后台异步执行)
            status                  # 显示状态
            undo <resource> <name>  # 回滚部署一个历史版本
                --to-revision=0     # 回滚到指定编号的版本。默认为 0 ,即上一个版本(非当前版本)
        scale <deployment|statefulset> <name>... --replicas=<int>   # 调整某个应用的 replicas 数量
        logs <pod>                  # 查看日志
            -c <name>               # --container ,选择 pod 中的某个容器
            --all-containers        # 选择 pod 中的所有容器
            -p                      # --previous ,选择之前的容器实例。比如一个 Pod 在重启前后存在不同的容器实例
            -f                      # --follow ,保持显示
            --tail 10               # 只显示最后几行。默认从头开始显示
            --timestamps            # 增加显示时间戳
            --since 1h              # 只显示最近一段时间的日志
            --since-time 2021-01-01T08:00:00Z # 只显示指定时刻开始的日志
        cp <pod>:<src_path> <dst_path>  # 将 Pod 中的文件拷贝到本机

        # 关于网络
        port-forward                # 让 kubectl 进程在本机监听一个端口,反向代理 Pod 的指定端口,常用于调试
            nginx 81:80             # 用本机的 81 端口,反向代理名为 nginx 的 Pod 的 80 端口
            deployment/nginx 81:80  # 反向代理名为 nginx 的 deployment ,随机选取其中一个 Pod 。即使目标 Pod 终止,也会继续转发,只有重启 kubectl 进程才会重新选取 Pod
                --address=127.0.0.1 # 监听的地址,默认只允许从本机访问
        proxy                       # 让 kubectl 进程在本机监听一个端口,反向代理 apiserver
            --port=8001
            --address=127.0.0.1
            --accept-hosts='^localhost$,^127\.0\.0\.1$' # 允许 HTTP 请求采用的目标地址,采用正则匹配
  • resource 类型可以是 nodes、pods、services 等。

    • 不区分单复数,比如 node 等价于 nodes 。
    • 可以通过逗号分隔符,同时指定多个 resource ,比如 nodes,pods
  • 例:以 deployment 形式部署一个 nginx 应用

    kubectl create deployment nginx --image=nginx:latest
    

    这样能部署简单的应用。但正式部署时,通常要为应用编写复杂的 YAML 配置文件,然后导入 k8s :

    kubectl apply -f xx.yaml
    
  • 例:当 Pod 故障时,通常执行这些命令进行排查

    kubectl get pod <name>            # 查看 Pod 的 phase
    kubectl describe pod <name>       # 查看 Pod status 中的信息
    kubectl logs <name> -f --tail 10  # 查看 Pod 的容器终端输出
    kubectl exec -it <name> -- bash   # 进入 Pod 容器终端
    
    kubectl get pod -o name -l k8s-app=nginx | xargs -I{} kubectl exec -it {} -- date   # 选出多个 Pod ,对它们同时执行命令
    

# crictl

  • crictl 是 k8s 官方发行的一个命令行工具,用于调用 kubelet CRI 接口,从而管理容器、镜像、Pod 。
    • 与 docker 命令相比,crictl 命令的缺点:
      • 功能少。
      • 命令语法不同,不方便习惯 docker 命令的用户使用。
    • 与 kubectl 命令相比,crictl 命令的缺点:
      • 只能管理容器、镜像、Pod ,不能管理其它 k8s 资源。
      • 只能调用本机的 CRI 接口,不能管理其它主机。
  • 安装:
  • 命令:
    crictl
        --runtime-endpoint <path> # 声明本机 CRI 的 sock 文件路径,从而与其交互。也可声明环境变量 CONTAINER_RUNTIME_ENDPOINT=xx
        version         # 显示 crictl、本机 CRI 的版本
    
        ps              # 列出所有容器
        images          # 列出所有镜像
        pods            # 列出所有 pod
    
        inspect  <id>   # 查看一个容器的详情
        inspecti <id>   # 查看一个镜像的详情
        pull <image>    # 拉取镜像
    
        exec -it <id> bash      # 进入一个容器的终端
        logs -f --tail 10 <id>  # 查看一个容器的日志
    
        rm  <id>        # 删除容器
        rmi <id>        # 删除镜像
        rmp <id>        # 删除 pod
    

# ctr

  • containerd 这个 CRI 项目,自带了一个管理命令 ctr 。
    • ctr 与 crictl 类似,遵循 CRI 规范,但功能少,不兼容 docker 命令语法。
  • 命令:
    ctr
        -a /run/containerd/containerd.sock  # --address ,containerd 的 sock 文件路径。也可声明环境变量 CONTAINERD_ADDRESS=xx
        -n default    # --namespace ,containerd 的命名空间。也可声明环境变量 CONTAINERD_NAMESPACE=xx
    
        namespace
            ls
    
        containers
            ls
            create ...
            rm <id>
    
        image
            ls
            pull <image>
            push <image>
            rm   <image>
    
    • containerd 设计了 namespace 的概念,而 CRI 规范没有该概念。
      • 用户可以创建多个 namespace ,隔离容器、镜像等资源。
      • 例如 Docker 采用 moby 命名空间,k8s 采用 k8s.io 命名空间。

# nerdctl

  • nerdctl 是 containerd 社区发行的另一个管理命令。
    • 支持 CRI 规范,因此是 ctr 的超集。
    • 兼备 docker、docker-compose 命令的功能,且命令语法相同。
  • 安装:
  • 命令:
    nerdctl
        # 兼容 ctr 的命令语法
        -a /run/containerd/containerd.sock
        -n default
    
        # 兼容 docker 的命令语法
        ps
        pull
        push
    
        # 兼容 docker-compose 的命令语法
        compose -f docker-compose.yml up