在之前的文章
介绍过, 通过任何node 的主机, 用kubectl 管理集群是很简单
无非就是两个步骤:
- 下载 k8s master 上的admin.conf
- 在当前主机配置 K8SCONFIG 环境变量指向 下载的config file
其他内网主机也适用
其实上面的方法也适用于内网的其他主机, 即使它不是k8s 集群的主机一员, 亲自测试,可行
外网主机的问题
如果想在k8s 集群内部网络用kubectl 访问 k8s 内网集群的话并不是那么简单
因为本文的k8s-master 并没有外网ip。
有两个理论上可行的方案
- 为k8s-master 分配1个外网ip, kubectl 经internet 去调用 k8s 集群的apiservice
- 在另1台有外网ip的同内网主机设置 反向代理 (nginx)
我首先尝试 的是方案2, 因为它能节省1个外网ip 的费用。
但是各种问题下, 又在google上找不到1个现有的方案例子, 就放弃了
所以本文的解决方案是方案1.
先申请外网ip
terrafrom 脚本:
resource "google_compute_address" "static-ip-1" {
name = "static-ip-1"
address_type = "EXTERNAL"
}
绑定外网ip 到 k8s-master 主机
ui 动态操作就好
在外网主机-我的本地laptop 设置kubectl
好了, 这个步骤 跟本文开头地道的基本一样, 只不过多了1个改 apiserver的步骤
1. 在本机安装kubectl
sudo pacman -S kubectl
最新版就好
下载 k8s-master 的admin.conf
cd ~
mkdir -p conf
cd conf
gcloud compute scp root@k8s-master:/etc/kubernetes/admin.conf .
配置K8SCONFIG
[gateman@manjaro-x13 conf]$ cat ~/.bashrc | grep KUBE
export KUBECONFIG=/home/gateman/conf/admin.conf
修改 admin.conf 的apiserver 地址
server: 那行改成 外网ip 地址
测试
[gateman@manjaro-x13 conf]$ kubectl get nodes
Unable to connect to the server: tls: failed to verify certificate: x509: certificate is valid for 10.96.0.1, 192.168.0.3, not 34.142.35.168
出错了
原因很简单, 因为apiserver 是https 协议, 上面的地址也看到了, k8s 默认的apiserver 证书 只cover了 10.96.0.1 和 192.168.0.3 的ip, 外网ip 是没有cover的
解决方法简单
alias kubectl=kubectl --insecure-skip-tls-verify
但是这个方法不够优雅, 不是所谓的Strategic solution, 只是个Tatical solution
为k8s 集群更新外网ip的 apiserver 证书
备份apiserver 证书
如果k8s 是用kubeadm方式安装的, 那么证书在 /etc/kubernetes/pki
gateman@k8s-master:~$ ls /etc/kubernetes/pki
apiserver-etcd-client.crt apiserver-kubelet-client.crt apiserver.crt backup ca.key front-proxy-ca.crt front-proxy-client.crt sa.key
apiserver-etcd-client.key apiserver-kubelet-client.key apiserver.key ca.crt etcd front-proxy-ca.key front-proxy-client.key sa.pub
gateman@k8s-master:~$ sudo cp apiserver.crt apiserver.key backup/
导出 kubeadm 配置
root@k8s-master:~# mkdir -p cert_external_ip/ && cd cert_external_ip/
kroot@k8s-master:~/cert_external_ip# kubectl -n kube-system get configmap kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' > kubeadm.yaml
修改 kubeadm, 添加 external ip
root@k8s-master:~/cert_external_ip# cat kubeadm.yaml
apiServer:
certSANs:
- 34.142.35.168
extraArgs:
authorization-mode: Node,RBAC
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.23.6
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
scheduler: {}
root@k8s-master:~/cert_external_ip#
就是 certSANs 的两行, 注意大小写
在生成新证书前 删除旧证书
cd /etc/kubernetes/pki
rm apiserver.crt apiserver.key
生成新的证书
kubeadm init phase certs apiserver --config kubeadm.yaml
注意这个命令会直接在 /etc/kubernetes/pki 生成新的证书, 当旧证书存在是不会生成, 所以之前要先拿走旧证书
重启 apiserver
无非就是shutdown apiserver
它会自动重新启动
docker kill $(docker ps | grep kube-apiserver | grep -v pause | awk '{print $1}')
更新 configMap 里的kubeadm配置
其实观察下上面导出 kubeadm.yaml 的命令, 其实是从configmap导出的
我们只在本地修改了 kubeadm.yaml 文件并基于它重新生成了apiserver key
到了这一步, 相信外网主机已经能远程登陆。
但是configmap里的 kubeadm 配置并没有更新
为了更strategic , 我们应该把修改后的kubeadm(增加了 certSANs) 更新回configMap.
不更新回去有什么问题?
- 下次再修改, 可能会忘了 ip的配置, 覆盖掉
- k8s集群的更新可能会覆盖apiserver 配置
命令
kubeadm config upload from-file --config kubeadm.yaml
但是我当前的版本1.26.3 是会出错的
root@k8s-master:~# kubeadm config upload from-file --config kubeadm.yaml
unknown flag: --config
To see the stack trace of this error execute with --v=5 or higher
work around:
手动更新:
kubectl edit configmap kubeadm-config -n kube-system
本地测试
pass!
[gateman@manjaro-x13 conf]$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 106d v1.23.6
k8s-node0 Ready <none> 106d v1.23.6
k8s-node1 Ready <none> 106d v1.23.6
k8s-node3 Ready <none> 86d v1.23.6
[gateman@manjaro-x13 conf]$