mmul.kubelab
这个角色可以用来部署一个 Kubernetes 集群,具备完全自动化和幂等性实现的多个组件。
特性
这个角色可以配置以启用以下所有特性:
单控制平面或多控制平面集群实现,使用 HAProxy 和 Keepalived 提供高可用性。
多网络插件 Flannel 和 Calico。
Kubernetes 仪表板。
用户管理,包括证书生成和
kubeconfig
文件更新。Ceph-CSI 存储类用于块设备。
MetalLB 负载均衡器用于裸金属环境。
Ingress NGINX 用于服务暴露。
Cert Manager 用于自动化证书管理。
使用 Ansible Playbook 安装集群
准备环境的最佳方式是使用 Python 虚拟环境,通过 pip3
安装 ansible:
user@lab ~ # python3 -m venv ansible
user@lab ~ # source ansible/bin/activate
(ansible) user@lab ~ # pip3 install ansible
正在收集 ansible
使用缓存的 ansible-7.5.0-py3-none-any.whl (43.6 MB)
...
成功安装 MarkupSafe-2.1.2 PyYAML-6.0 ansible-7.5.0 ansible-core-2.14.5 cffi-1.15.1 cryptography-40.0.2 jinja2-3.1.2 packaging-23.1 pycparser-2.21 resolvelib-0.8.1
然后,你需要这个角色,在这种情况下,使用 ansible-galaxy
是一个好的选择,可以使其自动化:
(ansible) user@lab ~ # ansible-galaxy install mmul.kubelab -p ansible/roles/
开始安装角色过程
- 正在下载角色 'kubelab',拥有者为 mmul
- 从 https://github.com/mmul-it/kubelab/archive/main.tar.gz 下载角色
- 正在提取 mmul.kubelab 到 /home/rasca/ansible/roles/mmul.kubelab
- mmul.kubelab (main) 安装成功
角色到位后,你可以再次使用 pip3
完成需求:
(ansible) user@lab ~ # pip3 install -r ansible/roles/mmul.kubelab/requirements.txt
...
成功安装 ansible-vault-2.1.0 cachetools-5.3.0 certifi-2023.5.7 charset-normalizer-3.1.0 google-auth-2.18.0 idna-3.4 kubernetes-26.1.0 oauthlib-3.2.2 pyasn1-0.5.0 pyasn1-modules-0.3.0 python-dateutil-2.8.2 requests-2.30.0 requests-oauthlib-1.3.1 rsa-4.9 six-1.16.0 urllib3-1.26.15 websocket-client-1.5.1
一旦安装完成后,通常会通过启动 tests/kubelab.yml
playbook 来使用这个角色,如下所示:
(ansible) user@lab ~ # ansible-playbook -i tests/inventory/kubelab tests/kubelab.yml
注意: 相关系统的日期和时间非常重要!执行 Ansible playbook 的机器和目标机器之间的时钟差异可能会导致证书验证失败。
注意: 你可以随时通过将 k8s_reset
设置为 true
来重置所有内容。这将重置整个集群,因此请谨慎使用:
(ansible) user@lab ~ # ansible-playbook -i tests/inventory/kubelab tests/kubelab.yml -e k8s_reset=true
安装后与集群交互
一旦 playbook 执行完成,与集群交互的最佳方式是使用 kubectl
命令,可以通过以下方式安装:
user@lab ~ # curl -s -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
user@lab ~ # chmod +x kubectl
user@lab ~ # sudo mv kubectl /usr/local/bin
Kubernetes 角色会生成一个本地目录,里面包含主要的 kubeconfig 文件,名为 admin.conf。使用它的最简单方法是导出 KUBECONFIG 变量,如下所示:
user@lab ~ # export KUBECONFIG=~/kubernetes/admin.conf
从现在开始直到会话结束,每次执行 kubectl
时都会依赖于该文件中的凭证:
user@lab ~ # kubectl cluster-info
Kubernetes 控制平面正在运行,地址为 https://192.168.122.199:8443
CoreDNS 正在运行,地址为 https://192.168.122.199:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
若要进一步调试和诊断集群问题,请使用 'kubectl cluster-info dump'。
user@lab ~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
kubernetes-1 Ready control-plane 26h v1.25.3
kubernetes-2 Ready control-plane 26h v1.25.3
kubernetes-3 Ready control-plane 26h v1.25.3
kubernetes-4 Ready <none> 26h v1.25.3
也可以使用不同的用户登录到集群,请查看 用户 部分获取详细信息。
配置
清单
典型的清单取决于你想要部署的内容,查看示例 kubelab
,你可以在主机文件中声明所有节点(请参阅 tests/inventory/kubelab/hosts):
# Kubernetes 主机
[kubelab]
kubernetes-1 k8s_role=control-plane run_non_infra_pods=true
kubernetes-2 k8s_role=control-plane run_non_infra_pods=true
kubernetes-3 k8s_role=control-plane run_non_infra_pods=true
kubernetes-4 k8s_role=worker
你将设置哪些节点充当控制平面,同时确定这些节点是否会运行非基础设施的 Pod(以使控制平面也成为工作节点)。
然后你可以在组文件(即 inventory/kubelab/group_vars/kubelab.yml)内定义所有附加配置,具体取决于你想要实现的内容。
Kubernetes 主机的主机组名称默认是 kubelab
,但可以通过声明 k8s_host_group
变量来重写。
Kubernetes 集群
如果你想要实现一个多控制平面的高可用集群,你需要指定这些变量:
k8s_cluster_name: kubelab
k8s_control_plane_node: kubernetes-1
k8s_control_plane_port: 6443
k8s_control_plane_cert_key: "91bded725a628a081d74888df8745172ed842fe30c7a3898b3c63ca98c7226fd"
k8s_multi_control_plane: true
k8s_balancer_VIP: 192.168.122.199
k8s_balancer_interface: eth0
k8s_balancer_port: 8443
k8s_balancer_password: "d6e284576158b1"
k8s_wait_timeout: 1200
k8s_control_plane_ports:
- 2379-2380/tcp
- 6443/tcp
- 8443/tcp
- 10250/tcp
- 10257/tcp
- 10259/tcp
这将从节点 kubernetes-1
启动集群,通过 k8s_multi_control_plane
启用多控制平面,并设置 VIP 地址和接口。
注意: 你会想要更改 k8s_control_plane_cert_key
和 k8s_balancer_password
以提高安全性。
注意: 目前只支持 rbd
供应。
网络插件
Kubernetes 角色支持 Flannel 和 Calico 网络插件。配置取决于你想要实现的插件。
对于 Flannel,你将需要类似以下内容:
# Flannel 插件
k8s_network_addon: flannel
k8s_network_addon_ports:
- 8285/udp
- 8472/udp
要查看如何实现 Calico,请查看 默认文件。
仪表板
Kubernetes 仪表板可以通过在配置中添加以下内容来实现:
k8s_dashboard_enable: true
安装完成后,通过使用 kubectl proxy
访问仪表板的最简单方法是访问相关的 URL http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/。
将会提示输入登录信息,你可以通过传递一个令牌来登录。默认情况下,Kubernetes 角色会创建一个名为 dashboard-user
的用户(你可以覆盖它)。
要获取令牌,你需要使用 kubectl
,如下所示:
user@lab ~ # kubectl -n kubernetes-dashboard create token dashboard-user
<你的令牌>
复制并粘贴上述命令的输出到提示符中,你将完成登录。
用户
你可以通过声明类似以下内容来向集群添加用户:
k8s_users:
- name: pod-viewer
namespace: default
role_name: pod-viewer-role
role_rules_apigroups: '""'
role_rules_resources: '"pods","pods/exec","pods/log"'
role_rules_verbs: '"*"'
rolebinding_name: pod-viewer-rolebinding
cert_expire_days: 3650
update_kube_config: true
这将创建一个本地目录,包含以下文件:
user@lab ~ # ls -1 kubernetes/users/
pod-viewer.crt
pod-viewer.csr
pod-viewer.key
users.conf
users-rolebindings.yaml
users-roles.yaml
然后可以使用 users.conf
文件访问集群,如下所示:
user@lab ~ # export KUBECONFIG=~/kubernetes/users/users.conf
rasca@catastrofe [~]> kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubelab kubelab kubernetes-admin
pod-viewer@kubelab kubelab pod-viewer default
user@lab ~ # kubectl config use-context pod-viewer@kubelab
切换到上下文 "pod-viewer@kubelab"。
user@lab ~ # kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kubernetes-admin@kubelab kubelab kubernetes-admin
* pod-viewer@kubelab kubelab pod-viewer default
user@lab ~ # kubectl get pods
在默认命名空间中未找到资源。
Ceph CSI
Kubernetes 角色实际上支持实现 Ceph CSI 存储类。可以如下定义:
k8s_ceph_csi_enable: true
k8s_ceph_csi_id: lab-ceph
k8s_ceph_csi_secret_userid: kubernetes
k8s_ceph_csi_secret_userkey: AQAWvU5jjBHSGhAAuAXtHFt0h05B5J/VHERGOA==
k8s_ceph_csi_clusterid: d046bbb0-4ee4-11ed-8f6f-525400f292ff
k8s_ceph_csi_pool: kubepool
k8s_ceph_csi_monitors:
- 192.168.122.11:6789
- 192.168.122.12:6789
- 192.168.122.13:6789
然后可以声明新的 PVC:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc
namespace: rasca
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
以及相关 Pod:
---
apiVersion: v1
kind: Pod
metadata:
name: csi-rbd-demo-pod
namespace: rasca
spec:
containers:
- name: web-server
image: nginx
volumeMounts:
- name: mypvc
mountPath: /var/lib/www/html
volumes:
- name: mypvc
persistentVolumeClaim:
claimName: rbd-pvc
readOnly: false
注意: 目前只支持 rbd
供应。
MetalLB
要启用 MetalLB,一种适用于裸金属 Kubernetes 集群的负载均衡器实现,只需声明:
k8s_metallb_enable: true
k8s_metallb_pools:
- name: 'first-pool'
addresses: '192.168.122.100-192.168.122.130'
这样就可以使用这个负载均衡器在声明的地址范围内创建 IP(查看下一个 ingress-nginx
示例以便理解)。
Ingress NGINX
要启用 Ingress NGINX,一个在 Kubernetes 中使用 NGINX 作为反向代理和负载均衡器的 Ingress 控制器,只需声明:
k8s_ingress_nginx_enable: true
这将安装 Ingress NGINX 控制器,可用于不同目的。
控制平面上的 Ingress NGINX
例如,可以通过在 HAProxy 管理的平衡 IP 上暴露 80
和 443
端口来使用 Ingress NGINX,如下所示:
k8s_ingress_nginx_enable: true
k8s_ingress_nginx_haproxy_conf: true
k8s_ingress_nginx_services:
- name: ingress-nginx-externalip
spec:
externalIPs:
- 192.168.122.199
ports:
- name: port-1
port: 80
protocol: TCP
- name: port-2
port: 443
protocol: TCP
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
这将使两个端口在平衡 IP(在这个例子中为 192.168.122.199
)上暴露,并使服务能够响应。
测试这个只需尝试以下操作:
$ kubectl create deployment demo --image=httpd --port=80
deployment.apps/demo 创建成功
$ kubectl expose deployment demo
service/demo 创建成功
$ kubectl create ingress demo --class=nginx \
--rule="demo.192.168.122.199.nip.io/*=demo:80" \
--annotation="nginx.ingress.kubernetes.io/service-upstream=true"
ingress.networking.k8s.io/demo 创建成功
$ curl http://demo.192.168.122.199.nip.io
<html><body><h1>它工作了!</h1></body></html>
或者测试 TLS:
$ kubectl create deployment demo --image=httpd --port=80
deployment.apps/demo 创建成功
$ kubectl expose deployment demo
service/demo 创建成功
$ openssl genrsa -out cert.key 2048
(没有输出)
$ openssl req -new -key cert.key -out cert.csr -subj "/CN=demo.192.168.122.199.nip.io"
(没有输出)
$ openssl x509 -req -days 366 -in cert.csr -signkey cert.key -out cert.crt
证书请求自签名成功
subject=CN = demo.192.168.122.199.nip.io
$ kubectl create secret tls tls-secret --cert=./cert.crt --key=./cert.key
secret/tls-secret 创建成功
$ kubectl create ingress demo --class=nginx \
--rule="demo.192.168.122.199.nip.io/*=demo:80,tls=tls-secret" \
--annotation="nginx.ingress.kubernetes.io/service-upstream=true"
ingress.networking.k8s.io/demo 创建成功
$ curl -k https://demo.192.168.122.199.nip.io
<html><body><h1>它工作了!</h1></body></html>
需要使用 --annotation="nginx.ingress.kubernetes.io/service-upstream=true"
的原因在于这个 ingress-nginx 问题。
与 MetalLB 结合使用的 Ingress NGINX
另一种方式是结合使用 MetalLB,通过声明一个 LoadBalancer
服务,如下所示:
k8s_ingress_nginx_enable: true
k8s_ingress_nginx_services:
- name: ingress-nginx-lb
spec:
type: LoadBalancer
loadBalancerIP: 192.168.122.100
ports:
- name: port-1
port: 80
protocol: TCP
- name: port-2
port: 443
protocol: TCP
这将安装与控制器相关的所有内容,并分配 MetalLB 提供的地址范围内的 loadBalancerIP
,并暴露这两个端口 80
和 443
。
Cert Manager
要启用 Cert Manager,一个自动化管理 Kubernetes 中证书的控制器,只需声明:
k8s_cert_manager_enable: true
k8s_cert_manager_issuers:
- name: letsencrypt
cluster: true
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt
solvers:
- http01:
ingress:
class: nginx
这将安装与控制器相关的所有内容,并创建一个将使用 letsencrypt
进行 HTTP01 挑战解析的集群发行者。
一旦安装完成并且你想要暴露一个应用程序,你可以使用类似以下 YAML 进行测试:
apiVersion: v1
kind: Namespace
metadata:
name: rasca
---
apiVersion: v1
kind: ConfigMap
metadata:
name: index-html
namespace: rasca
data:
index.html: |
这是我美妙的 Web 服务器!
---
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: rasca
labels:
app: nginx
spec:
containers:
- name: web-server
image: nginx
volumeMounts:
- name: docroot
mountPath: /usr/share/nginx/html
volumes:
- name: docroot
configMap:
name: index-html
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: rasca
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
name: nginx-ingress
namespace: rasca
spec:
ingressClassName: nginx
rules:
- host: nginx.apps.kubelab.mmul.it
http:
paths:
- backend:
service:
name: nginx-service
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- nginx.apps.kubelab.mmul.it
secretName: nginx.apps.kubelab.mmul.it
如果你仔细查看最后一个资源,名为 nginx-ingress
的 Ingress
将会看到两个重要部分:
在
metadata
->annotations
下的注释cert-manager.io/cluster-issuer: letsencrypt
。在
spec:
->tls
下的主机声明。
有了这些设置,在一些时间后,你将能够提供为暴露的服务的证书。
许可
MIT
作者信息
Raoul Scarazzini (rascasoft)