Month: 1月 2019

故障排查记录

Case 1:

CPU 和内存都被打满了,同时发现硬盘 IO 也很高。

ps -eo pid,ppid,cmd,%mem,mem,%cpu --sort=-%mem | head -n 50

发现 kswapd0 偶尔会占用很高的 CPU,而这个进程是在内存满的时候负责在内存和 swap 之间交换。也就是问题的根源是内存满了,而 kswapd0 开始在内存和 swap 之间反复读写文件,导致 CPU 和 IO 也涨了起来,这时候应该找到内存暴涨的根源,进而解决问题。

[1] https://askubuntu.com/questions/259739/kswapd0-is-taking-a-lot-of-cpu

kubernetes 初探——服务治理

服务治理有两种方式:

  • 一种是直接在服务中集成熔断降级等操作
  • 一种是使用 sidecar 模式,有公共组件来处理

两种模式的区别如图:

相关概念

Service. 如果一个 Deployment 对外(pod 外)提供服务的话,可以暴露为 Service。它是服务的抽象,通过 kube-proxy 和 DNS 等提供负载均衡给后端 RC 定义的 Pod。服务一共有三种类型:

  • clusterIP. 服务暴露在集群内部的一个虚拟 IP,生命周期和服务相同
  • nodePort. 暴露在所有 Node 上的服务端口,不建议在生产环境使用。
  • LoadBalancer,通过外部的 LB,暴露对应的服务。

另外还可以使用 Ingress Controller. Service 只是对集群内部暴露了服务,Ingress Controller 用于把 Service 再对外暴露。就相当于一个反向代理。

如果一个 deployment 需要对集群内部或者是外部提供服务的话,可以使用 service。

这时将创建一个 clusterIP,需要特别注意的是,这个 clusterIP 也是虚拟的,并没有和任何 pod 绑定,而是绑定到了服务上,可以理解为绑定到了这个服务对应的内部负载均衡上,并且是不变的。即使你的 Deployment 中指定了多个副本,那么也只有这一个 clusterIP,pod 的创建和销毁也都不会影响到 clusterIP。

使用 ingres 部署一个服务

ClusterIP + Proxy

ClusterIP 是集群内部提供服务的默认方式。可以采用 kubelet proxy + ClusterIP 的方式临时提供对外服务。

NodePort IP

NodePort 方式在每个 host 上都开一个端口来对外提供服务,适合一些临时性的服务。

ClusterIP + LoadBalancer

使用云厂商提供的 LoadBalancer 来提供服务,唯一的缺点是每一个服务会消耗一个 IP,比较贵。

除此之外,还可以使用 MetalLB 等等第三方的 LB。

Ingress + LB

Ingress 并不是 K8S 的一种服务类型,实际上他本身是一个 Service,然后路由到不同的服务。实际上 Ingress 就是反向代理。

但是要暴露出去 Ingress 服务本身,可能还是要使用 NodePort 或者 LoadBalancer。

Internet -> Loadbalancer -> Ingress Controller -> Ingress Rules -> K8s-Services -> Replicas

Internet -> NodePort -> Ingress Controller -> Ingress Rules -> K8s-Services -> Replicas

在 K3S 中自带了一个 service lb,所以只要确保 ingress controller 第一个暴露出 loadbalancer 类型的 80 端口,就能自动通过 80 端口访问了。

Traefik Ingress Controller

Traefik 在 2.0 中不止支持了 K8S 默认的 ingress,还自己定义了一种 IngressRoute 类型的 CRD。千万不要用这个 IngressRoute,他还不支持证书,简直就是废物。

尽量不要使用 Traefik,bug 太多了。

nginx Ingress Controller

nginx 毕竟是官方支持的 ingress,比较稳定,而且性能也比较好。

Cert Manager

Cert-Manager 用于管理 k8s 集群内部的证书。

Cert-Manager 中最重要的三个概念是:

  • Issuer, 只能在当前命名空间颁发证书
  • ClusterIssuer,可以在所有 namespace 颁发证书
  • Certificate, 颁发的证书

实战

安装 cert-manager

kubectl create namespace cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml
kubectl get pods -n cert-manager  # 可以看到几个在运行的 pod

安装一个 clusterissuer

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: <your>@<email>.<com> # 替换掉这个
    privateKeySecretRef:
      name: prod-issuer-account-key
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
      - http01:
          ingress:
            class: traefik
        selector: {}

然后,kubectl apply -f letsencrypt.yaml

安装一个服务

# 创建一个简单的 deployment,这里我们用了 rancher logos 这个服务
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rancher-logo-app
  namespace: default
spec:
  selector:
    matchLabels:
      name: rancher-logo-backend
  template:
    metadata:
      labels:
        name: rancher-logo-backend
    spec:
      containers:
        - name: backend
          image: ruanbekker/logos:rancher
          ports:
            - containerPort: 80
---
# 创建一个 service,暴露了 80 端口,注意这里不需要暴露 443 端口
apiVersion: v1
kind: Service
metadata:
  name: rancher-logo-service
  namespace: default
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    name: rancher-logo-backend
---
# 创建一个 ingress,并在 annotation 中指定了使用 cluster-issuer
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: rancher-logo-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik  # 使用 traefik 做 ingress
    cert-manager.io/cluster-issuer: letsencrypt-prod  # 使用 cluster-issuer
    traefik.ingress.kubernetes.io/redirect-entry-point: https  # TODO 貌似没用
spec:
  tls:
    - secretName: logos-ezly-tv-tls
      hosts:
        - logos.ezly.tv
  rules:
  - host: logos.ezly.tv  # ingress 的配置
    http:
      paths:
        - path: /
          backend:
            serviceName: rancher-logo-service  # 指向的 service
            servicePort: 80

需要注意的是,https 证书的发放需要时间,可能得等 1 分钟左右才能从 https 协议访问。

参考

  1. https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0
  2. https://stackoverflow.com/questions/45079988/ingress-vs-load-balancer
  3. https://sysadmins.co.za/https-using-letsencrypt-and-traefik-with-k3s/
  4. https://medium.com/@jmrobles/free-ssl-certificate-for-your-kubernetes-cluster-with-rancher-2cf6559adeba
  5. 这个教程有些问题,但是也有参考价值。https://community.hetzner.com/tutorials/howto-k8s-traefik-certmanager
  6. https://stackoverflow.com/questions/58553510/cant-get-certs-working-with-cert-manager
  7. Service Mesh 的本质、价值和应用探索
  8. Istio, K8S 的微服务支持
  9. 微服务之熔断、降级、限流
  10. 微服务化之服务拆分与服务发现
  11. https://sysadmins.co.za/https-using-letsencrypt-and-traefik-with-k3s/