k8s实用知识点总结

文章目录

      • 1. 资源配额
      • 2. 关于探针
      • 3. Pod日志查看
        • 3.1 进入指定Pod中的指定容器
        • 3.2 查看Pod日志
      • 4. 版本
      • 5. 使用 `ExternalName` Service 代理OSS静态
      • 6. 让Master节点参与调度
      • 7. 删除Pod
      • 8. 删除命名空间
      • 9. 创建拉取镜像的凭证
      • 10. 升级deployment/svc等(通用)
      • 11. 在Pod中添加host
      • 12. 开启远程debug
      • 13. 定向调度
      • 附:一些常用的命令

1. 资源配额

1. 预留和限制的概念

  • 预留:即至少需要的资源,对应于requestsCpurequestsMemory
  • 资源限制:最大资源限制,对应于limitsCpulimitsMemory

2. 单位的含义

  • 内存:常用的单位为MiBGi,和常规单位的关系如下为:
1 MiB = 2^20 bytes = 1024 kibibytes = 1048576 bytes(以2为底数)
1 MB = 1000KB(以10为底数)
  • CPU:常用单位为毫核(mmilli),或者直接是核(没有单位,如1核直接表示为1),换算关系为:1个核=1000m,当然也可以使用占比来表示,如:1/4个核=0.25,半个核=0.5,1个整核=1。

注:在rancher中部署应用时,经常遇到deployment does not have minimum availability异常,此时适当调大资源限额可以解决大部分的问题,下面是Chart模板中常用的配置:

resources:
  limits:
    memory: {{ .Values.resources.limits.memory }}
    cpu: {{ .Values.resources.limits.cpu }}
  requests:
    memory: {{ .Values.resources.requests.memory }}
    cpu: {{ .Values.resources.requests.cpu }}

2. 关于探针

 K8S中的探针应该是必不可少的一部分,参照文档,理了理,探针主要分为2类:

  • liveness probe:存活探针,它可以决定何时重启容器,比如存活探针在应用运行过程中遇到死锁(应用确实是正在运行的,但无法获取结果),这种情况往往是由于代码中存在bug,尽管如此,但存活探针的存在可以让应用更加具有可用性;
  • readiness probe:就绪探针,它可以决定一个容器何时就绪,准备接受外部的流量。如果说某个Pod已经就绪表示该Pod中的所有容器都已经就绪,当一个Pod处于未就绪的状态,他将会从负载均衡中移除;

实际观测,只有当2类探针同时检测通过,Pod才算启动成功,下面是探针的配置方式:

  readinessProbe:
    enabled: true
    httpGet:
      path: "/healthcheck"
      port: 8080
    periodSeconds: 20
    initialDelaySeconds: 60
    failureThreshold: 3
  
  livenessProbe:
    enabled: true
    httpGet:
      path: "/healthcheck"
      port: 8080
    initialDelaySeconds: 180
    periodSeconds: 30
    failureThreshold: 3

实际开发中,发现后端的Server启动用这套探针没啥问题,但前端的Server(使用node)启动的过程非常不稳定,build和拉取依赖的过程耗时特别长,基本都会重启好几遍容器才能成功,我曾经试图去调节存活探针的initialDelaySeconds参数,但如果这个过程快的话我岂不是要浪费一些时间,最终发现调节失败的阈值failureThreshold会更加方便。

 具体探针的行为可以有如下的一些:

1.HTTP
java中探针往往都是通过调用类似于go的HTTP接口,示例:

    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

2.具体指令
探针检测的具体行为可以自己定义,比如:

    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

上述是将探针的行为定义为Linux中的cat命令

3.TCP
比如一些ES的连接可能会用到TCP

    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

3. Pod日志查看

3.1 进入指定Pod中的指定容器

 在rancher中,权限一般给的很严,一般不会使用docker命令直接进入容器,而是要使用kubectl命令才能进入:

kubectl exec -it <podName> -c <containerName> -n <namespace> -- -- /bin/bash

# 退出容器
exit

如果Pod中只有1个容器,上述命令可以直接简写为kubectl exec -it -n -- -- /bin/bash,进入容器后即可为所欲为了(●ˇ∀ˇ●)。

【注】上述通过kubectl exec可以拓展为任意容器中的命令,形如kubectl exec -n -- xxx,只要容器中可以执行 xxx命令,那就可以通过上述的方式在不进入容器的情况下对容器执行一些命令。

3.2 查看Pod日志

 Pod日志可以直接通过logsdescribe查看,具体示例如下:

# 1. logs方式
kubectl logs <pod_name> -c <container_name> -n <namespace>
# 2. describe方式
kubectl describe pod <pod_name> -n <namespace>

得到的结果也是2个不同的,logs方式得到的日志是我们是部署应用时指定挂载目录位置中的日志,如deployment中在指定容器规约时:

spec:
  containers:
  	...
    volumeMounts:
    - mountPath: /data/logs/paas
      name: log-dir

那此时看到的日志就是/data/logs/paas/xxx.log的内容。

describe方式得到的日志是关于pod行为的日志,最典型的就是Pod节点的分配Scheduled、镜像的拉取Pulling/Pulled、容器的创建Created及运行Started、探针检测Unhealthy/Healthy

4. 版本

 和Helm类似的,K8S集群和K8S集群客户端是两回事,在写Chart时需要一个属性kubeVersion,查看版本信息:

Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.7", GitCommit:"6f482974b76db3f1e0f5d24605a9d1d38fad9a2b", GitTreeState:"clean", BuildDate:"2019-03-25T02:52:13Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.5", GitCommit:"753b2dbc622f5cc417845f0ff8a77f539a4213ea", GitTreeState:"clean", BuildDate:"2018-11-26T14:31:35Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}

我们需要的是服务端版本,指的是GitVersion:"v1.11.5",所以kubeVersion: 1.11.5

5. 使用 ExternalName Service 代理OSS静态

 通常使用Service去发现Server,对于正常应用都可以应对,但当代理OSS静态资源时,有点尴尬,集群内是没有明确的Server对应,此时必须使用ExternalName类型的Service去解决,示例如下:

# 额外的ExternalName Service用于OSS静态代理
kind: Service
apiVersion: v1
metadata:
  name: hhu-static
spec:
  type: ExternalName
  # 此处为OSS访问域名,取回CNAME与之映射
  externalName: hhu-prod-static.oss-cn-beijing-internal.aliyuncs.com

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: server-hhu
  annotations:
    kubernetes.io/ingress.class: nginx-ingress
spec:
  rules:
  - host: k8s-www.hhu.com
    http:
      paths:
      - path: /*
        backend:
          serviceName: hhu-static
          servicePort: 80

注:OSS还需要额外绑定k8s-www.hhu.com域名,否则无法进行代理。

6. 让Master节点参与调度

 默认情况下,k8s集群是不让master节点参与Pod的调度,通过如下的命令可以改变这种行为:

# 让master节点参与调度
kubectl taint node <k8s-master-hostname> node-role.kubernetes.io/master-

# 恢复master节点的Master Only状态
kubectl taint node <k8s-master-hostname> node-role.kubernetes.io/master=""

7. 删除Pod

# 正常删除
kubectl delete pod xxx

# 强删
kubectl delete pod <pod name> --force --grace-period=0 -n <namespace>

8. 删除命名空间

 删除命名空间的准确步骤如下:

  1. 查看待删除的命名空间中是否存在资源:kubectl get all -n xxx,然后清空资源(务必确认这个步骤);
  2. 删除namespace:kubectl delete ns xxx
  3. 确认命名空间已删除:kubectl get ns

【注】:

  • 如果上述第一步没有完全删除待删除命名空间下的资源,那第三步可能出现该命名空间一直处于 Terminating 的状态;
  • 无法删除 Pod 时可采用强制手段:kubectl delete pod --force --grace-period=0 -n
  • 如果上述手段无效解决 Terminating 状态的namespace,可以直接升级namespace,去除yaml文件中的finalizers属性:
# 编辑命名空间的配置文件
kubectl edit ns xxx

# 删除如下属性保存退出即可
  finalizers:
  - kubernetes

9. 创建拉取镜像的凭证

# 创建凭证
kubectl -n <name-space> create secret docker-registry <secret-name> \
--docker-server=registry.xxx.com \
--docker-username=<user-name> \
--docker-password=<password> \
--docker-email=[email protected]

# 删除密码
kubectl delete secret <secret-name>

在控制器的规约中指定拉取镜像的密码名字即可,在spec中直接使用:

spec: 
  template: 
    spec: 
      imagePullSecrets:
      - name: -name>

【注】上述的--docker-xxx选项中的值可能包含了一些特殊的值(比如#或者@等符号),此时需要使用英文的引号'xxx'来包裹,这种写法也是比较推荐的,不会出现问题。

10. 升级deployment/svc等(通用)

 比如升级deployment:kubectl edit deployment apollo-portal修改保存后就会自动升级,然后通过kubectl rollout status deployment apollo-portal即可看到更新的状态(不动不是卡住,是正在执行一个阶段),直到... rolled out即表示deployment升级成功,其对应的Pod也会重新创建并运行,下面是升级apollo-portal的日志:

# 升级 apollo-portal 的deployment
kubectl edit deployment apollo-portal
# 修改保存后退出出现下面的打印结果
deployment.extensions/apollo-portal edited

# 查看升级过程
kubectl rollout status deployment apollo-portal
# 下面是升级日志
Waiting for deployment "apollo-portal" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "apollo-portal" rollout to finish: 1 old replicas are pending termination...

11. 在Pod中添加host

 测试环境中,由于少了域名解析的这一层,通常需要额外绑定一些host,此时可以通过hostAliases向Pod中添加指定的host,形如:

spec:
  hostAliases:
  - ip: "127.0.0.1"
    hostnames:
    - "foo.local"
    - "bar.local"
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"

通过名命令kubectl exec server-746ddf6747-9kmx7 -n -- cat /etc/hosts可以检验。

12. 开启远程debug

 在k8s中为了可以进行remote debug,可以做如下配置:

  1. java的启动参数增加:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=
  2. 在Service中指定一个端口(使用nodePort类型)映射到remote-debug-port
  3. 直接使用集群中任意节点的IP加nodePort形式即可(:),nodeIp可以是任意节点IP;

【注】
在上述第2步中,由于remote-debug使用的端口使用的是NodePort,所以在定义Service时需要额外将type也指定为NodePort,否者默认是ClusterIP类型,在该类型不允许使用nodePort来做映射,即类似于:

apiVersion: v1
kind: Service
# 省略部分配置
spec:
  ports:
  - port: 80
    targetPort: {{ .Values.service.port }}
    name: http
  - port: {{.Values.remoteDebugPort}}
    targetPort: {{.Values.remoteDebugPort}}
    nodePort: {{.Values.remoteDebugNodePort}}
    name: remote-debug
  selector:
    service-cluster: {{ .Values.deploy.serviceCluster }}
    app: {{ .Values.deploy.app }}
    project-type: java
  type: NodePort

K8S在创建Service时,将会给其分配IP地址(默认是cluster IP,即只能在集群中访问),Service可以将任意请求到port的端口映射到targetPort端口,完成最终请求,默认情况下,为了便利,targetPort设置为和port一样的值。

ServiceType,即在定义Service时,spec.type字段,默认为ClusterIP,相关释义如下:

  • ClusterIP:使用集群内部的IP暴露服务,只能在集群内部访问服务,默认值;
  • NodePort:将服务暴露在集群中每个节点的一个指定静态端口上(即port.NodePort),将会自动创建一个ClusterIp的Service,然后将NodePort的服务路由到上面,此时集群外部可以访问集群内的服务;
  • LoadBalancer:使用云提供商(如阿里云)提供的负载均衡暴露服务,指向集群外部负载均衡的NodePortClusterIpService会被自动创建;
  • ExternalName(CoreDNS1.7+):externalName字段通过返回CNAME记录的方式,将Service映射到上面。

13. 定向调度

 有些场景需要将Pod调度到指定节点上,步骤如下:

  1. 给节点添加标签:kubectl label node
  2. 在定义Pod时,直接通过NodeSelector: 即可;

附:一些常用的命令

# 使用 -o yaml 选项查看 deployment 的yaml文件
kubectl get deployment my-nginx -n hhu-pro -o yaml

# 使用 -o wide 选项查看 pod 的详细信息,可查看到分配的worker节点
kubectl get pods -n hhu-pro -o wide

# 运行时动态修改Pod副本数量,controller-type可能为deployment或者rc,controller-name为controller的名字
kubectl scale <controller-type> <controller-name> --replicas=3

你可能感兴趣的:(k8s)