侧边栏壁纸
博主头像
枕头下放双臭袜子博主等级

今我何功德,曾不事农桑

  • 累计撰写 166 篇文章
  • 累计创建 32 个标签
  • 累计收到 0 条评论
k8s

kubernetes-tips

枕头下放双臭袜子
2021-07-16 / 0 评论 / 0 点赞 / 315 阅读 / 8,223 字 / 正在检测是否收录...

0、权限-安全

使用网络策略可以限制Pod的出站和入站流量,比如设置Pod不能访问特定的公网地址,比如设置Pod不能被设定的IP段访问,比如设置拒绝所有入站和出站流量,仅允许特定来源。文档

1、RS历史版本

Deployment 中可以设置.spec.revisionHistoryLimit字段来指定保留此Deployment的多少个旧有ReplicaSet。其余的RS将在后台被垃圾回收。默认情况下。此值为10

显式将此字段设置为 0 将导致 Deployment 的所有历史记录被清空,因此 Deployment 将无法回滚

2、删除Evited的Pod

# kubectl -n kube-system  get pods | grep Evicted |awk '{print$1}'|xargs kubectl -n kube-system delete pods

3、kube-proxy 是 ipvs/iptables?

个人见解

# 可以通过查看kube-proxy使用configmap的字段“mode”
kubectl get configmap -n kube-system
kubectl describe configmap -n kube-system kube-proxy

kubeproxy_configmap.png

4、kubernetes的服务发现

参考来源

① kubernetes的svc 对后端pod的负载均衡是4层的轮询,所以同一个连接里发起的所有请求都会进入同一个 Pod。因为在 4 层工作,所以对于 7 层的 HTTP 头或者 Cookie 之类的东西是无法感知的
② Kubernetes 使用 DNS 作为服务注册表

注册过程大致如下:

① 向 API Server 用 POST 方式提交一个新的 Service 定义;
② 这个请求需要经过认证、鉴权以及其它的准入策略检查过程之后才会放行;
③ Service 得到一个 ClusterIP(虚拟 IP 地址),并保存到集群数据仓库;
④ 在集群范围内传播 Service 配置;
⑤ 集群 DNS 服务得知该 Service 的创建,据此创建必要的 DNS A 记录。
上面过程中,第 5 个步骤是关键环节。集群 DNS 使用的是 CoreDNS,以 Kubernetes 原生应用的形式运行。CoreDNS 实现了一个控制器,会对 API Server 进行监听,一旦发现有新建的 Service 对象,就创建一个从 Service 名称映射到 ClusterIP 的域名记录。这样 Service 就不必自行向 DNS 进行注册,CoreDNS 控制器会关注新创建的 Service 对象,并实现后续的 DNS 过程。

DNS 中注册的名称就是 metadata.name,而 ClusterIP 则由 Kubernetes 自行分配。
svcdiscovery1.jpg

要使用服务发现功能,每个 Pod 都需要知道集群 DNS 的位置才能使用它。因此每个 Pod 中的每个容器的 /etc/resolv.conf 文件都被配置为使用集群 DNS 进行解析。

每个新 Service 对象的配置,其中包含它的 ClusterIP 以及 Endpoints 对象(其中包含健康 Pod 的列表),都会被发送给 每个节点上的 kube-proxy 进程。kube-proxy 会创建 iptables 或者 IPVS 规则,告知节点捕获目标为 Service ClusterIP 的流量,并根据 Endpoints 对象的内容转发给对应的 Pod。
也就是说每次节点内核处理到目标为 Service 网络的数据包时,都会对数据包的 Header 进行改写,把目标 IP 改为 Service Endpoints 对象中的健康 Pod 的 IP。

服务发现总结

创建新的 Service 对象时,会得到一个虚拟 IP,被称为 ClusterIP。服务名及其 ClusterIP 被自动注册到集群 DNS 中,并且会创建相关的 Endpoints 对象用于保存符合标签条件的健康 Pod 的列表,Service 对象会向列表中的 Pod 转发流量。
与此同时集群中所有节点都会配置相应的 iptables/IPVS 规则,监听目标为 ClusterIP 的流量并转发给真实的 Pod IP。这个过程如下图所示:

svcdiscovery2.jpg

一个 Pod 需要用 Service 连接其它 Pod。首先向集群 DNS 发出查询,把 Service 名称解析为 ClusterIP,然后把流量发送给位于 Service 网络的 ClusterIP 上。然而没有到 Service 网络的路由,所以 Pod 把流量发送给它的缺省网关。这一行为导致流量被转发给 Pod 所在节点的网卡,然后是节点的缺省网关。这个操作中,节点的内核修改了数据包 Header 中的目标 IP,使其转向健康的 Pod。

svcdiscovery3.jpg

5、将configmap挂载成pod内的文件

现在有一个configmap:

configmap_mount_pod_file_1.png

这个configmap的键名为文件名,键值是文件内容。需求是把这个configmap以文件形式挂载到容器中的特定目录下,deploy yaml部分如下:

configmap_mount_pod_file_2.png

6、重启deployment小技巧

参考来源

# 修改<deployment-name>、<container-name>、<namespace>
kubectl patch -n <namespace> deployment <deployment-name> -p '{"spec":{"template":{"spec":{"containers":[{"name":"<container-name>","env":[{"name":"RESTART_","value":"'$(date +%s)'"}]}]}}}}'

有时候我们会需要重启Deployment,原因可能是:

1、docker image使用的是latest tag,这个latest在docker image registry已经更新了,我们需要重启deployment来使用新的latest
2、Pod运行缓慢但是还活着,就是想重启它一下
3、ConfigMap/Secret变更了,想重启一下应用新配置

当Deployment spec没有发生任何变化,即使你kubectl apply -f deployment-spec.yaml也是没用的,因为K8S会认为你这个没有变化就什么都不做了。

基本思路就是给Container添加一个无关紧要的环境变量,这个环境变量的值就是时间戳,而这个时间戳则是每次执行上述命令的系统当前时间。这样一来对于K8S来讲这个Deployment spec就变化了,就可以像Updating a deployment一样,重启Pod了

7、Configmap

Configmap可以挂载到容器中的Env上,此种形式下,更新Configmap后,使用该 ConfigMap 挂载的 Env 不会同步更新。

Configmap可以以volumes的形式挂载到容器中的文件,此种形式下,更新Configmap后,使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新.

不管基于哪种形式使用了ConfigMap挂载的配置,更新 ConfigMap 目前都不会触发相关 Pod 的滚动更新,都需要通过滚动更新Pod的方式来强制重新挂载ConfigMap

8、定义一个local volume作为pv持久卷

参考

apiVersion: v1
kind: PersistentVolume
metadata:
  name: xxxx-pv
spec:
  capacity:
    storage: 20Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /data/es-data/
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - k8s-master

nodeAffinity字段是必须配置的,k8s依赖于这个标签为你定义的Pods在正确的nodes节点上找到需要使用的local volumes。

使用volumeMode字段时,需要启用BlockVolume 这一Alpha feature特性。

volumeMode字段的默认值是Filesystem,但也支持配置为Block,这样就会把node节点的local volume作为容器的一个裸块设备挂载使用。

定义Local volume时必须有nodeAffinity,k8s会基于你所定义得Affinity规则在特定的node上使用local volume所定义的路径,而且pod也必然会被调度到该节点上,只有这样才能使用该local volume!
错误示例:

首先创建local volume类型的pv时,nodeAffinity选择的是k8s-master-01节点,然后创建该pv,创建对应的pvc,当pod引用该pvc后,pod就瞬间pending了。原因是我的测试集群k8s-master-01被打了污点,不能被调度,node-01、node-02又没有local volume,导致pod无法被调度,所以瞬间pending

kubernetestips81.png
kubernetestips82.png
kubernetestips83.png
报错:
kubernetestips84.png

9、使用curl发送带json数据的POST请求

curl -X POST -d 'json内容' --header "Content-Type: application/json" POD_IP:POD_PORT/INTERFACE

10、创建一个local storageclass 并设置为默认storageclass

参考
参考

首先创建一个storageclass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

通过patch将其修改为default sc(修改is-default-class参数)

kubectl patch storageclass local-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

11、--since查看pod标准日志输出

# 返回当前21h前的标准日志输出
kubectl logs -n NameSpace Pod_Name --since=21h > ingress.log
# --since-time='' 仅返回给定时间后的标准输出日志

docker logs -f –since="2018-0208" –tail=100 CONTAINER_ID
docker还支持时间段,--since="" –until ""

docker logs日志原理:

当我们输入docker logs的时候会转化为Docker Client向Docker Daemon发起请求,Docker Daemon 在运行容器时会去创建一个协程(goroutine),绑定了整个容器内所有进程的标准输出文件描述符。因此容器内应用的所有只要是标准输出日志,都会被 goroutine 接收,Docker Daemon会根据容器id和日志类型读取日志内容,最终会输出到用户终端上并且通过json格式存放在/var/lib/docker/containers目录下。

Docker官网关于日志说明

12、init状态Pod日志查看

# 若pod处于init状态,则需要通过docker ps查看其日志

#获取对应的pod name(STATUS是init的pod_name)
kubectl get pod -A --field-selector status.phase=Init
#通过docker ps 获取该pod的中的CONTAINER ID
docker ps | grep pod_name
#通过docker log获取对应的日志信息
docker logs CONTAINER_ID

13、查看kubectl命令与API Server的交互过程

kubectl get ns -v=9
kubectl xx xxx -v=9

14、headless service

headless service相当于没有cluster ip

普通的service都会由一个cluster ip,客户端访问过程是,客户端 -> service name ->(core dns解析到pod)

kubernetestips141.png

headless的过程是,客户端 -> service name ->(iptables解析到pod name)

配置 Selector:对定义了 selector 的 Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 Service 的后端 Pod上。见下图:

kubernetestips142.png

不配置 Selector:对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建 Endpoints 记录。

headless service多与statfulset结合使用(Headless Service的对应的每一个Endpoints,即每一个Pod,都会有对应的DNS域名;这样Pod之间就可以互相访问)

15、一键更新k8s集群证书

github项目地址

# kubeadm集群查看证书过期时间
kubeadm alpha certs check-expiration

该命令显示 /etc/kubernetes/pki 文件夹中的客户端证书以及 kubeadm 使用的 KUBECONFIG 文件中嵌入的客户端证书的到期时间/剩余时间。
kubeadm 不能管理由外部 CA 签名的证书,如果是外部得证书,需要自己手动去管理证书的更新
另外需要说明的是上面的列表中没有包含 kubelet.conf,因为 kubeadm 将 kubelet 配置为自动更新证书

查看 apiserver 的证书的有效期来验证是否更新成功:
$ echo | openssl s_client -showcerts -connect 127.0.0.1:6443 -servername api 2>/dev/null | openssl x509 -noout -enddate

16、nodePort会在集群所有主机上监听该端口

17、configmap内容被修改会同时更新pod中引用的configmap内容,但是如果pod中的程序使用了该configmap,那么该程序需要重新加载该configmap

18、通过docker overlay2的目录名查找对应容器名称

cd /var/lib/docker/overlay2
du -sch * | sort -rn | more
docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.Id}}, {{.Name}}, {{.GraphDriver.Data.WorkDir}}' | grep

19、helm plugin list显示无插件但是helm plugin install却报错插件已安装

解决办法(检查下目录结构再酌情删除):
rm -rf ${HOME}/.config/helm/
rm -rf ${HOME}/.cache/helm/
rm -rf ${HOME}/.local/share/helm

20、通过docker overlay2目录名查找对应容器名称

一般情况下,docker overlay2目录位置是:/var/lib/docker/overlay2/

这个目录可以通过docker的配置文件(/etc/docker/daemon.json)内找到

进入overlay2目录后可以通过du命令查看谁占用空间比较大:
du -sh * | sort -rn | more

随后可以通过目录名查找对应容器名:
docker ps -q | xargs docker inspect –format '{{.State.Pid}}, {{.Name}}, {{.GraphDriver.Data.WorkDir}}' | grep “xxxxxxxx”
如果发现有目录查不到,通常是因为容器已经被删掉了,目录没有清理

21、docker ps --size

要检查每个正在运行的容器的大小只需使用command的 --size参数即可

22、taint、toleration相关

NodeAffinity节点亲和性,是Pod上定义的一种属性,使Pod能够按我们的要求调度到某个Node上,而Taints则恰恰相反,它可以让Node拒绝运行Pod,甚至驱逐Pod。Taints(污点)是Node的一个属性,设置了Taints(污点)后,因为有了污点,所以Kubernetes是不会将Pod调度到这个Node上的,于是Kubernetes就给Pod设置了个属性Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。如果需要toleration的pod一定调度到taint的机器上,还需要和nodeName/nodeSelector配合使用。因此 Taints(污点)通常与Tolerations(容忍)配合使用。Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,Taint应用于Node上,而toleration则应用于Pod上(Toleration是可选的)

23、secret

create secret时有三种类型:

1、docker-registry 顾名思义用来认证镜像仓库

2、generic 从本地文件、文件夹、字符值创建secret

3、tls 创建一个tls类型的secret

kubectl create secret generic xxxxxxx -n xxxxxxx --from-file=xxxxx

参考
参考
一个secret挂载到容器中某个路径下,默认要独占一个目录,不能与其他挂载进去的configmap或者其他secret共占一个目录,如下所示:

ports:
        - containerPort: 8309
        volumeMounts:
          - name: app-configmap
            mountPath: /conf/
          # ios p12证书
          #- name: app-secret-p12
          # mountPath: /pem/
            #subPath: apiclient_cert.p12
      volumes:
        - name: app-configmap
          configMap:
            name: moneycenterconfig
#        - name: app-secret-p12
#          projected:
#            sources:
#              secret:
#                secretName: apiclient-cert-p12
          ##secret:
          ##  secretName: apiclient-cert-p12

24、docker ps看不到相关的k8s pod

pod会根据相应算法调度到集群任意节点,如果该pod没有被调度到当前执行docke ps的机器上,自然不能够通过docker ps命令看到相应的pod。
再进一步,如果 pod 运行成功了,并且你当前正在被调度 pod 的节点上查找容器,那么问题可能是 kubernetes 使用了不同的容器运行时

25、k8s日志标准输出

不同的容器运行时对应的日志保存目录不尽相同,以 Docker 为例,所有真实日志均在 /var/lib/docker/ 路径下,这个目录下都是以容器ID命名的文件夹,容器ID可以通过describe pod的Container ID 字段来获取到

26、kops可以在aws上安装kubernetes

0

评论