本地 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