Skip to Content

本地 k8s 集群搭建

Table of Contents

Kubernetes 现在已经成为容器编排的事实标准,是明确的容器云的未来,社区高涨的热情,ServiceMesh、Knative、CNCF 等等无数关键字无一不是在反复突出他的关键地位。 如果架构、服务化的未来是容器云,那么 Kubernetes 必然是最核心的基础。 如果只是希望学习 Kubernetes 的使用,比如基于 Kubernetes 运行一些测试,那最简单的方式就是使用 minikube, 只需要保证有一个可用的 HTTP_PROXY 可用保证其依赖的容器运行时(比如 Docker)可以正常下载 Google 相应的镜像文件,一条命令即可拥有一个单机版 Kubernetes 环境。

minikube start \
    --docker-env HTTP_PROXY=${http_proxy} \
    --docker-env HTTPS_PROXY=${https_proxy} \
    --docker-env NO_PROXY=192.168.99.0/24

在有代理的情况下,先把需要的镜像下载完成,然后在去除环境变量中的代理,来部署 k8s 服务。

但是,如果想更进一步的深入了解 Kubernetes 的更多细节,则需要手动部署,甚至是从源码编译来部署 Kubernetes,我应邀在极客时间做了一个小视频, 并配套了一个部署项目 k8s-start,来说明这个问题,感兴趣的同学可以先看看这个项目。下面是一些学习和使用中遇到的一些值得关注的问题。

product_uuid 与 MAC 地址唯一性

我习惯使用 parallels 在本机虚拟出 Linux 来作为部署的服务器,而且为了更快速的按需生成虚拟机,我还有一个好用的项目来驱动,但是快速 clone 虚拟机会带来直接的问题就是 product_uuid 的唯一性得不到保障(sudo cat /sys/class/dmi/id/product_uuid),虽然 MAC 地址这些可以重新生成,但是 product_uuid 却不可以(这个数据是内核数据的一个映射,从内存中读出来的),所以最后只能独立安装与集群节点数一致的虚拟机。

安装文档 真是一个字不能漏。

kube-dashboard 服务导出

这里我使用 ingress( 选用 Nginx-ingress-controller 实现) 的方式来导出服务,当然还有 其他方式 同样可以导出 k8s 集群中的服务。

ingress 服务导出机制

为了解决 Pod IP 漂移的问题 kubernetes 引入了 Service 的概念,通过类似 VIP 的思路来使用 Service 对象将 Pod 提供的服务抽象出来, 而 Ingress 对象却又像 Service 的 Service,用于将 kubernetes 集群中的 Service 导出给集群以外的网络访问。类似于我们通常的反向代理的角色。

Ingress 服务导出机制主要由 Ingress 对象(刻画相应的反向代理规则 ingress rules)、 ingress controller(通常是一个 Deployment 对象,比如 Nginx-ingress-controller, 根据 Ingress 对象和被代理后端 Service 的变化来自动进行更新的 Nginx 负载均衡器)、Ingress Service(将 Ingress controller 导出为提供接入层的服务); 而其他 ingress-secret、nginx-ingress-serviceaccount 等则作为 kubernetes 体系的辅助对象,辅助 Ingress 完成服务导出功能。

可以通俗的吧 Ingress 理解为 kubernetes 内置的一种全局的,为了代理不同后端 Service 而设置的负载均衡服务。它是 kubernetes 对 “反向代理” 的一种抽象,而 default-backend 则是自定义的 404 页面(比如 nginx-default-backend)。

kube-dashboard TLS

Kube-dashboard 默认提供的是 HTTPS 服务,所以对应的 Ingress 对象也必须支持导出 HTTPS,好在这点现有的 Ingress 方案都支持的比较好,这里仍然以 Ingress-Nginx 为例。

Ingress-Nginx 以 注释 的方式来提供自定义 Ingress 对象的行为。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-dashboard
  namespace: kube-system
  annotations:
    nginx.ingress.kubernetes.io/secure-backends: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  tls:
  - hosts:
    - dashboard-ingress.idevz.org
    secretName: ingress-secret
  rules:
  - host: dashboard-ingress.idevz.org
    http:
      paths:
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 443

kube-dashboard 权限

默认的 kube-dashboard 项目, kubernetes-dashboard 账号的权限是非常低的,为了得到更高的权限,可以重新添加一个更高权限的账号,比如 kubernetes-dashboard-admin

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-admin
  namespace: kube-system
  
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard-admin
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard-admin
  namespace: kube-system

Kubernetes 服务导出方式

NodePort

直接导出对应的 NodePort 端口,不足之处在于会在所有的节点都开启 Port 监听,如果服务规模大的时候,端口资源将是一大问题。

LoadBalancer Service

适用于公有云上的 kubernetes 服务,当有 LoadBalancer 类型的服务提交到公有云后,公有云的 kubernetes 服务就会调用 CloudProvider 在公有云上创建对应的负载均衡服务(显然为每个服务都创建负载均衡服务是不必要也比较浪费资源的)。

ExternalName

这是 1.7 版本后 kube-dns 提供的功能,目前没有实践(@TODO)。

分配公有 IP 地址(externalIPs)

在指定的 externalIPs 上导出服务,便捷。

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: ClusterIP
  externalIPs:
  - 10.211.55.151
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
微信公众号 / Vanilla-OpenResty