Kubernetes工作节点的自动加入方法
数据中心的插图
当前的家庭实验室背景对于一直关注我将一个功能齐全的 Kubernetes 集群带入生活,并在 illumos 中外部运行控制平面的那些人,现在终于可以拥有一个完全符合规范的集群了。
Cilium的v1.16版本终于可以通过BGP发布ClusterIP,实现了集成的可能性,这意味着外部控制平面可以通过由动态准入控制器提供的webhook进行连接,这些控制器实际上运行在数据平面,作为控制平面的扩展。
Cilium的下一个版本v1.17将带来一个备受期待的功能特性——一个无需kube-proxy的集群通过了CNCF Kubernetes认证测试(相关问题(#9207)最近已解决并合并到主分支)。这是一个好消息,因为它允许使用无侧car的Cilium服务网格构建一个100%符合标准的集群!
我直接并放弃了当前的 IPAM 预留并卸载了再重新安装了 Cilium 到 1.17.0-pre.0,使用了以下 helm 参数:
# 声明 Apiserver IP 和端口
K8S_API_SERVER=
K8S_API_PORT=
# 需要填写具体的服务器IP和端口
航向值设置:
cat << EOF > cilium-helm-values.yaml
用户提供的值:
bgpControlPlane:
enabled: true
bpf:
lbExternalClusterIP: true
cluster:
name: default-cluster
cluster.name: default-cluster
gatewayAPI:
enabled: true
hubble:
启用: true
metrics:
dashboards:
annotations:
grafana_folder: Cilium
启用: true
namespace: monitoring
enableOpenMetrics: true
启用:
- dns
- drop
- tcp
- icmp
- 流: 源上下文=工作负载名称|保留标识; 目标上下文=工作负载名称|保留标识
- kafka: 标签上下文=源命名空间,源工作负载,目标命名空间,目标工作负载,流量方向; 源上下文=工作负载名称|保留标识; 目标上下文=工作负载名称|保留标识
- httpV2: exemplars=true; 标签上下文=源IP, 源命名空间, 源工作负载, 目标IP, 目标命名空间, 目标工作负载, 流量方向; 源上下文=工作负载名称|保留标识; 目标上下文=工作负载名称|保留标识
serviceMonitor:
启用: true
operator:
prometheus:
启用: true
serviceMonitor:
启用: true
prometheus:
启用: true
serviceMonitor:
启用: true
relay:
启用: true
prometheus:
启用: true
serviceMonitor:
启用: true
ui:
启用: true
ingressController:
default: true
启用: true
负载均衡器模式: 专用
ipam:
模式: cluster-pool
k8sServiceHost: ${K8S_API_SERVER}
k8sServicePort: ${K8S_API_PORT}
kubeProxyReplacement: true
operator:
复本: 1
ciliumPods的滚动更新: true
EOF
同时,我终于能够升级到 Cilium BGP 控制平面 v2(https://docs.cilium.io/en/latest/network/bgp-control-plane/bgp-control-plane-v2/),这对我来说是一个特别兴奋的时刻。
BGP 控制平面 v2 的自定义资源定义在结构上有些许差异,但在基本结构上变化不大。组件被拆分成了 CiliumBGPClusterConfig
、CiliumBGPPeerConfig
和 CiliumBGPAdvertisement
。需要注意一下细节,CiliumLoadBalancerIPPool
的结构已从 .spec.cidr
更改为 .spec.blocks
(为了增强灵活性)。
为了使用v2,需要创建以下文件。
# 声明应通过BGP通告的CIDR地址段
LB_CIDR=
# 集群ASN
CLUSTER_ASN=
# 对等路由器的ASN和IP
PEER_ASN=
PEER_IP=
创建一个IP池设置
下面的命令将输出到 `cilium-ippool.yaml` 文件中,内容如下:
cat << "结束标记" > cilium-ippool.yaml
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: ippool
spec:
blocks:
- cidr: ${LB_CIDR}
disabled: false
结束标记
块定义了 CIDR 范围,其中 apiVersion
和 kind
是特定于 Cilium 项目的术语。blocks
包含一个 CIDR 范围定义,disabled
表示是否禁用。
对于BGP,可以设置为如下所示的配置:
cat << EOF > cilium-bgp-v2.yaml
---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
name: cilium-bgp
spec:
nodeSelector:
matchLabels:
bgp: worker
bgpInstances:
- name: "instance_asn"
localASN: ${CLUSTER_ASN}
peers:
- name: "peer_asn"
peerASN: ${PEER_ASN}
peerAddress: ${PEER_IP}
peerConfigRef:
name: "cilium-peer"
---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
name: cilium-peer
spec:
transport:
peerPort: 179
families:
- afi: ipv4
safi: unicast
advertisements:
matchLabels:
advertise: "bgp"
---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
name: bgp-advertisements
labels:
advertise: 通告: bgp
spec:
advertisements:
- advertisementType: "PodCIDR"
attributes:
communities:
standard: [ "65000:99" ]
- advertisementType: "Service"
service:
addresses:
- ClusterIP
- ExternalIP
- LoadBalancerIP
selector: # <-- (选择所有服务)
matchExpressions:
- {key: somekey, operator: NotIn, values: ['never-used-value']}
EOF
順便一提,這是在我的 Kubernetes 集群中運行的符合性測試結果,控制平面節點運行在 Illumos 上,而工作節點則運行在 Linux 上。挺厲害的,對不對?
运行了 7197 个规格中的 402 个测试,耗时约 6431.74 秒
成功啦!-- 402 通过 | 0 失败 | 6795 跳过了
通过了
Ginkgo 运行了 1 套测试套件,耗时约 1 小时 47 分 15 秒
测试套件通过了
# 基于证书的机构
# 基于证书的机构
# 证书机构
因为我之前已经详细写过配置CA的过程,我不会再重复那些步骤。相反,我将介绍让CFSSL Api运行起来所需的步骤。
虽然以下步骤是针对illumos描述的,但对于Linux(或BSD)系统来说,也会采取类似的步骤,只是使用不同的服务清单。
可以使用各种方式(如下所述 <https://kubernetes.io/docs/tasks/administer-cluster/certificates/> )让证书颁发机构运行起来,但我们会专注于 kubeadm 选择的那个方式(它支持带有 `-serve` 标志的 API)。
API 需要一个后端支持,你可以选择使用鹅(goose)项目(<https://github.com/cloudflare/cfssl/tree/master/certdb>),或者参考这篇博客文章<https://bouchaud.org/blog/en/posts/initializing-root-intermediate-ca-with-cfssl/>。
以下步骤会修改对CA的一些先前配置。
首先,让我们声明一些关键的变量。
# 创建一个用于与CA进行身份验证的密钥
AUTH_KEY=$(openssl rand -hex 16) 生成一个16位的随机密钥
# 运行CFSSL API的主机的IP
CA_URL
* 创建一个 SQLite 后端吧
cat << EOF > sqlite.sql
创建表 证书 (
序列号 blob NOT NULL,
权威密钥标识符 blob NOT NULL,
ca_label blob,
状态 blob NOT NULL,
撤销原因 int,
过期 timestamp,
撤销时间 timestamp,
发行时间 timestamp,
生效时间 timestamp,
元数据 blob,
sans blob,
通用名称 blob,
pem blob NOT NULL,
主键(序列号, 权威密钥标识符)
);
创建表 ocsp响应 (
序列号 blob NOT NULL,
权威密钥标识符 blob NOT NULL,
正文 blob NOT NULL,
过期 timestamp,
主键(序列号, 权威密钥标识符),
外键(序列号, 权威密钥标识符) 引用 证书(序列号, 权威密钥标识符)
);
EOF
cat sqlite.sql | sqlite3 /opt/ooce/etc/certdb.db
* 创建配置文件以开启数据库访问
cat << EOF > /opt/ooce/etc/sqlite_db.json
{"driver":"sqlite3","data_source":"/opt/ooce/etc/certdb.db"}
EOF
cat << EOF > ocsp-csr.json
{
"CN": "OCSP 签名者",
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
"C": "SE",
"ST": ".",
"L": "Stockholm"
}
]
}
EOF
* 创建或修改中间的Kubernetes证书颁发机构(CA),以便为OCSP和CRL设置URL。
cat << EOF > kubernetes-ca/kubernetes-ca-config.json
{
"signing": {
"default": {
"auth_key": "key1",
"ocsp_url": "http://${CA_URL}:8889",
"crl_url": "http://${CA_URL}:8888/crl",
"expiry": "过期时间 168h"
},
"profiles": {
"中间证书": {
"auth_key": "key1",
"expiry": "过期时间 43800h",
"usages": [
"signing",
"key encipherment",
"cert sign",
"crl sign"
],
"ca_constraint": {
"is_ca": true,
"max_path_len": 1
}
},
"ocsp": {
"auth_key": "key1",
"usages": [
"digital signature",
"OCSP 签名"
],
"expiry": "过期时间 26280h"
},
"www": {
"auth_key": "key1",
"expiry": "过期时间 8760h",
"usages": [
"signing",
"key encipherment",
"服务器认证"
]
},
"kubelet": {
"expiry": "过期时间 8760h",
"auth_key": "key1",
"usages": [
"signing",
"key encipherment",
"客户端认证",
"服务器认证"
]
},
"client": {
"auth_key": "key1",
"expiry": "过期时间 8760h",
"usages": [
"signing",
"key encipherment",
"客户端认证"
]
}
}
},
"auth_keys": {
"key1": {
"key": "${AUTH_KEY}",
"type": "standard"
}
}
}
EOF
cfssl gencert -ca=kubernetes-ca/kubernetes-ca.pem -ca-key=kubernetes-ca/kubernetes-ca-key.pem -config=kubernetes-ca/kubernetes-ca-config.json -profile="ocsp" ocsp-csr.json |cfssljson -bare ocsp
* 把文件放到API要使用的位置里:
将 `kubernetes-ca/kubernetes-ca{{,-key}.pem,-config.json}` 和 `ocsp{,-key}.pem` 复制到 `/opt/ooce/etc/` 目录下。
* 创建一个 SMF(System Management Framework)方法脚本文件(例如对于 systemd 来说,这样做是有意义的,选择 `exec` 后的可执行参数):
cat << EOF > /lib/svc/method/cfssl
#
# 本文件的内容受以下许可的条款约束:
# 通用开发和分发许可证("许可")。
# 除非遵守该许可,否则您不得使用此文件。
#
# 您可以从 usr/src/OPENSOLARIS.LICENSE 或 http://www.opensolaris.org/os/licensing 获取许可副本。
# 请参阅许可中规定的具体语言,了解许可的权限和限制。
#
# 在分发受保护的代码时,在每个文件中包含此 CDDL 标头,并在 usr/src/OPENSOLARIS.LICENSE 中包括许可文件。
# 如适用,请在 CDDL 标头之后添加以下内容,使用方括号 "[]" 中的字段替换您自己的标识信息: 版权所有 [yyyy] [版权拥有者的姓名]
#
# CDDL 标头结束
#
#
# 版权所有 © 2008 Sun Microsystems, Inc. 保留所有权利。
# 使用受许可条款的约束。
#
#ident "%Z%%M% %I% %E% SMI"
#
# 启动/停止客户端 LDAP 服务
#
. /lib/svc/share/smf_include.sh
case "\$1" in
'start')
exec /opt/ooce/bin/cfssl serve -address=0.0.0.0 -port=8888 \
-db-config=/opt/ooce/etc/sqlite_db.json \
-ca=/opt/ooce/etc/kubernetes-ca.pem -ca-key=/opt/ooce/etc/kubernetes-ca-key.pem \
-config=/opt/ooce/etc/kubernetes-ca-config.json \
-responder=/opt/ooce/etc/ocsp.pem \
-responder-key=/opt/ooce/etc/ocsp-key.pem > /var/log/cfssl.log \
2>&1 &
;;
'stop')
exec /usr/bin/pkill cfssl
;;
*)
echo "用法: \$0 start 或 stop"
exit 1
;;
esac
EOF
chmod +x /lib/svc/method/cfssl
* 服务声明文件:
cat << EOF > /lib/svc/method/cfssl
#
# 本文件的内容受通用开发和分发许可证("许可")的约束。
# 除非遵守许可协议中的条款,否则不得使用本文件。
#
# 您可以在usr/src/OPENSOLARIS.LICENSE或http://www.opensolaris.org/os/licensing/获取许可协议的副本。
# 请参阅许可协议了解具体的条款规定,以确定许可和限制的条件。
#
# 分发受许可代码时,在每个文件中包含此CDDL标题的内容,并在usr/src/OPENSOLARIS.LICENSE处包含许可文件。
# 如适用,请在CDDL标题下方加上以下内容,用方括号"[]"中的字段替换您自己的标识信息: 版权所有[yyyy] [版权所有者姓名]
#
# CDDL标题结束
#
#
# 版权 © 2008 Sun Microsystems, Inc. 保留所有权利。
# 使用受许可协议的约束。
#
#ident "%Z%%M% %I% %E% SMI"
#
# 启动和停止客户端LDAP服务
#
. /lib/svc/share/smf_include.sh
case "\$1" in
'start')
exec /opt/ooce/bin/cfssl serve -address=0.0.0.0 -port=8888 \
-db-config=/opt/ooce/etc/sqlite_db.json \
-ca=/opt/ooce/etc/kubernetes-ca.pem -ca-key=/opt/ooce/etc/kubernetes-ca-key.pem \
-config=/opt/ooce/etc/kubernetes-ca-config.json \
-responder=/opt/ooce/etc/ocsp.pem \
-responder-key=/opt/ooce/etc/ocsp-key.pem > /var/log/cfssl.log \
2>&1 &
;;
'stop')
exec /usr/bin/pkill cfssl
;;
*)
echo "用法: \$0 { start | stop }"
exit 1
;;
esac
EOF
chmod +x /lib/svc/method/cfssl
# 云配置工作节点
在之前的帖子中已经描述了工作节点的设置,这里我只简要描述 `runcmd:` 段落中的步骤。被注释的部分用作虚拟化 guest 的示例(我创建了一个模板并进行克隆以节省时间,因此不需要重新安装客户端二进制文件,如下解释):
runcmd:
- modprobe overlay
- modprobe br_netfilter
- sysctl --system 2>/dev/null
#- echo "deb [signed-by=/usr/share/keyrings/libcontainers-archive-keyring.gpg] https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_22.04/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
#- echo "deb [signed-by=/usr/share/keyrings/libcontainers-crio-archive-keyring.gpg] https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.28/xUbuntu_22.04/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:1.28.list
#- mkdir -p /usr/share/keyrings /var/lib/kubelet
#- curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_22.04/Release.key | gpg --dearmor -o /usr/share/keyrings/libcontainers-archive-keyring.gpg
#- curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.28/xUbuntu_22.04/Release.key | gpg --dearmor -o /usr/share/keyrings/libcontainers-crio-archive-keyring.gpg
#- curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
#- echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
#- export DEBIAN_FRONTEND=noninteractive KUBECONFIG=/etc/kubernetes/admin.conf
#- DEBIAN_FRONTEND=noninteractive apt-get update -q -y
#- DEBIAN_FRONTEND=noninteractive apt-get install -y cri-o cri-o-runc apt-transport-https ca-certificates curl gnupg-agent software-properties-common jq golang-cfssl
#- systemctl daemon-reload
#- systemctl enable --now crio
#- DEBIAN_FRONTEND=noninteractive apt-get install -q -y kubelet=1.28.3-1.1 kubectl=1.28.3-1.1
#- DEBIAN_FRONTEND=noninteractive apt-mark hold kubelet kubectl
- |
curl -q -s -d '{"label": "primary"}' http://${CA_URL}:8888/api/v1/cfssl/info |jq -r '.result.certificate' > /var/lib/kubelet/ca.pem
- |
cat <<CIEOF > /var/lib/kubelet/worker-csr.json
{
"CN": "system:node:\$(cat /etc/hostname)",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"\$(cat /etc/hostname)",
"\$(ip -4 -br --json a |jq -r '.[1].addr_info[].local')"
],
"names": [
{
"O": "system:nodes"
}
]
}
CIEOF
- |
cat <<CIEOF | cfssl gencert -config /dev/stdin -profile=client -profile=kubelet /var/lib/kubelet/worker-csr.json |cfssljson -bare /var/lib/kubelet/worker
{
"auth_keys" : {
"key1" : {
"type" : "standard",
"key" : "${AUTH_KEY}"
}
},
"signing" : {
"default" : {
"auth_remote" : {
"remote" : "cfssl_server",
"auth_key" : "key1"
}
}
},
"remotes" : {
"cfssl_server" : "${CA_URL}"
}
}
CIEOF
- KUBECONFIG=/var/lib/kubelet/kubeconfig kubectl config set-cluster default-cluster --server=https://${K8S_API}:6443 --certificate-authority /var/lib/kubelet/ca.pem --embed-certs
- KUBECONFIG=/var/lib/kubelet/kubeconfig kubectl config set-credentials system:node:\$(cat /etc/hostname) --client-key /var/lib/kubelet/worker-key.pem --client-certificate /var/lib/kubelet/worker.pem --embed-certs
- KUBECONFIG=/var/lib/kubelet/kubeconfig kubectl config set-context default-system --cluster default-cluster --user system:node:\$(cat /etc/hostname)
- KUBECONFIG=/var/lib/kubelet/kubeconfig kubectl config use-context default-system
- systemctl enable --now kubelet
这里将发生的情况是,工作节点将获取CA证书作为基础,利用其主机名和IP地址来生成证书签名请求。
通过CFSSL API接口,CA将回复工作节点(Worker Node)的证书和密钥。
我一直在成功地运行这个来自动加入正在运行的作为bhyve客机的工作节点,一个RK1节点(Rockchip RK3558),一个CM4节点,以及一个通过pxe和cloud-init/autoinstall安装的裸机节点。
敬请期待…
共同学习,写下你的评论
评论加载中...
作者其他优质文章