配置对多集群的访问
一、背景
当使用 kubectl
连接k8s集群时,kubectl
默认会在 $HOME/.kube
目录下查找名为 config
的文件,该文件用于配置对k8s集群的访问,下文统称为 config
文件。
通过设置 KUBECONFIG
环境变量可以指定使用的 config
文件。
同时当使用 kubectl
时可以通过使用 --kubeconfig
参数引用不同k8s集群的 config
文件来达到访问不同集群的目的,但显然每次使用命令时额外添加一个参数的方式不太友好。
通过扩展k8s提供的 config
文件,将集群、用户和上下文定义在一个 config
文件中之后,用户可以使用 kubectl config use-context
命令快速地在集群之间进行切换。
二、配置多集群访问示例
2.1 使用脚本提取密钥
在原始的 .kube/config
文件中,ca.crt
等内容较多在多集群时显示混乱,将其换成 ca.crt
这种文件形式便于区分。下面的python脚本 k2file.py
将某集群 config
文件中的 ca.crt
等内容另存至对应的 ca.crt
文件中。
#!/usr/bin/env python
#!encoding=utf-8
## 解析kubectl的config文件, 生成ca.crt, client.crt和client.key文件.
## 用法: python k2file.py /etc/kubernetes/admin.conf
## 有个问题: script_dir 总是获取 k2file.py 脚本所在的目录, 而非执行脚本所在的目录.
## 而使用 open() 打开并创建文件时, 如果不写绝对路径, 就会使用以脚本所在位置的相对路径.
## 需要使用 os.getcwd() 代替, 这样得到的是执行脚本时所在的目录, 而非脚本本身所在的目录.
## python2内置yaml模块, python3则需要使用pip安装PyYAML
import yaml
import sys
import os
import base64
def parse_yaml(target_file, curr_dir):
# 打开yaml文件
file = open(target_file, 'r')
file_data = file.read()
file.close()
# 将字符串转化为字典或列表
data = yaml.safe_load(file_data)
ca_crt = data['clusters'][0]['cluster']['certificate-authority-data']
client_crt = data['users'][0]['user']['client-certificate-data']
client_key = data['users'][0]['user']['client-key-data']
file_ca_crt = open(curr_dir + '/ca.crt', 'wb')
file_ca_crt.write(base64.b64decode(ca_crt))
file_ca_crt.close()
file_client_crt = open(curr_dir + '/client.crt', 'wb')
file_client_crt.write(base64.b64decode(client_crt))
file_client_crt.close()
file_client_key = open(curr_dir + '/client.key', 'wb')
file_client_key.write(base64.b64decode(client_key))
file_client_key.close()
if __name__ == '__main__':
## python k2file.py /etc/kubernetes/admin.conf 的 argv 中不包含 `python`
if len(sys.argv) == 3:
print("请指定配置文件路径")
sys.exit(-1)
target_file = ''
curr_dir = os.getcwd()
## 判断 python 版本.
if sys.version_info < (3, 0):
## python2
import os
target_file = os.path.join(curr_dir, sys.argv[1])
else:
## python3
from pathlib import Path
target_file = Path(curr_dir).joinpath(sys.argv[1])
print('yaml file: ', target_file)
parse_yaml(target_file, curr_dir)
复制代码
脚本原理:读取某个k8s集群的 /etc/kubernetes/admin.conf
文件。将其中 ca.crt
,client.crt
,client.key
等字符串提取出来, 存到 ca.crt
,client.crt
,client.key
这样的文件中。
2.2 将生成的密钥文件统一存放
示例统一存放至 /root/th/.kube
目录中,最终目录结构如下:
[root@k8smaster01 ~/th/.kube]# tree
.
├── certs.d
│ └── dev
│ ├── ca.crt
| ├── client.crt
| └── client.key
| └── test
│ ├── ca.crt
| ├── client.crt
| └── client.key
└── config
复制代码
注意: 下一步需要编辑的 config
文件,如果用户已经拥有一个集群,可以使用 kubectl
与集群进行交互, 那么很可能在 $HOME/.kube
目录下有一个名为 config
的文件,可以参考该文件配置。
2.3 编辑 config
文件,定义集群、用户和上下文
/root/th/.kube/config
文件说明见注释:
apiVersion: v1
kind: Config
preferences: {}
# k8s集群定义
clusters:
- cluster:
certificate-authority: certs.d/dev/ca.crt
server: https://xxx.xxx.xxx.xxx:xxxx #指定master配置的负载均衡地址(apiserver的性能很差, 生产一般均配置负载均衡), 具体值可以参考k8s的master节点 $HOME/.kube/config 文件中配置.
name: dev # 集群名称,与contexts.context.cluster对应
- cluster:
certificate-authority: certs.d/test/ca.crt
server: https://xxx.xxx.xxx.xxx:xxxx
name: test # 集群名称,与contexts.context.cluster对应
# 用户定义(一般与集群一对一)
users:
- name: dev-admin # 用户名称,与contexts.context.user对应
user:
client-certificate: certs.d/dev/client.crt
client-key: certs.d/dev/client.key
- name: test-admin # 用户名称,与contexts.context.user对应
user:
client-certificate: certs.d/test/client.crt
client-key: certs.d/test/client.key
# 上下文定义(针对不同集群可以根据namespace区分设置多个上下文)
contexts:
- context:
cluster: dev # 集群名称
namespace: frontend # 上下文命名空间
user: dev-admin # 用户名称
name: dev-frontend # 上下文名称(kubectl进行集群切换时所用)
- context:
cluster: dev
namespace: storage
user: dev-admin
name: dev-storage
- context:
cluster: test
namespace: frontend
user: test-admin
name: test-frontend
- context:
cluster: test
namespace: storage
user: test-admin
name: test-storage
# 当前上下文名称(表示当前kubectl连接的集群)
current-context: dev-frontend
复制代码
**注意:**也可通过 kubectl config
相关命令操作config文件,如:将集群信息添加至配置文件中,详见官方文档。
2.4 配置 KUBECONFIG
环境变量
export KUBECONFIG=/root/th/.kube/config
复制代码
小技巧:
可以配置 .bashrc
文件,简化 kubectl
等命令的操作,建立会话连接时通过 source .bashrc
命令加载用户自定义配置,.bashrc
示例(关于 .bashrc
文件会另写一篇文章介绍):
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
#1、常用配置
# 使用ls命令列出文件列表时加上颜色显示等
alias ls='/bin/ls -F --color=tty --show-control-chars'
alias grep='grep --color=auto'
# 修改终端显示样式
PS1="\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@\h \[\e[36;40m\]\w\[\e[0m\]]\\$ "
#3、docker相关
alias dk='docker'
alias dc='docker-compose'
## @function: 清空目标容器的日志(docker clear log)
## $1: 目标容器名称或id
function dclog() {
local log_path=$(docker inspect -f '{{.LogPath}}' $1)
## 清空目标文件
:>$log_path
}
## @function: 进入目标容器网络空间
## $1: 目标容器名称/ID
function denter(){
local dpid=$(docker inspect -f "{{.State.Pid}}" $1)
nsenter -t $dpid -n /bin/sh
}
## @function: 进入目标容器网络空间
## $1: 目标容器名称/ID
function dnsenter() {
local dpid=$(docker inspect -f "{{.State.Pid}}" $1)
nsenter -t $dpid -n /bin/sh
}
## @function: 清理不用的容器和镜像
function dclean() {
## 删除旧容器, 不会删除当前正在运行的容器
docker rm $(docker ps -a -q)
## 移除本地多余的历史镜像
docker images | grep '<none>' | awk '{print $3}' | xargs docker rmi
}
## @function: 进入容器内部, 优先尝试 bash 终端
## @note: alias dex='docker exec -it'
## $1: 目标 Pod 名称
function dex() {
## 如果把标准输出也 null 掉, 当目标 Pod 有正常 bash 时就无法进行交互, 终端会卡死.
## docker exec -it $1 bash 1>/dev/null 2>/dev/null
docker exec -it $1 bash 2>/dev/null
if (( $? != 0 )); then
echo 'bash does exist, try to use sh'
docker exec -it $1 sh
fi
}
#4、k8s相关
export KUBECONFIG=/root/th/.kube/config
alias k='kubectl'
alias kap='kubectl apply -f'
alias kde='kubectl describe'
alias kgl='kubectl get --show-labels'
## @function: 获取当前的context列表
## @note: kc -> kubectl context
function kc() {
kubectl config get-contexts
}
## @function: 切换当前的context为目标$1
## @note: ks -> kubectl switch
function ks() {
kubectl config use-context $1
}
## @function: 打印目标资源的详细信息
## $1: 目标资源类型(必选)
## $2: 目标资源名称(必选)
## $3: 目标资源的所属空间, 如 -n namespace(可选)
function kwd() {
## $@ 表示传入的所有参数.
kubectl get -o wide $@
}
## @function: 打印目标资源的 yaml 信息
## $1: 目标资源类型(必选)
## $2: 目标资源名称(必选)
## $3: 目标资源的所属空间, 如 -n namespace(可选)
function kya() {
## $@ 表示传入的所有参数.
kubectl get -o yaml $@
}
## @function: 进入容器内部, 优先尝试 bash 终端
## @note: alias kex='kubectl exec -it'
## $1: 目标 Pod 名称(必选)
## $2: 目标资源的所属空间, 如 -n namespace(可选)
function kex() {
## 如果把标准输出也 null 掉, 当目标 Pod 有正常 bash 时就无法进行交互, 终端会卡死.
## kubectl exec -it $1 bash 1>/dev/null 2>/dev/null
kubectl exec -it $@ bash 2>/dev/null
if (( $? != 0 )); then
echo 'bash does exist, try to use sh'
kubectl exec -it $@ sh
fi
}
## @function: 删除某个资源对象
## $1: 目标资源名称(必选)
## $2: 目标资源的所属空间, 如 -n namespace(可选)
function kkill() {
## $@ 表示传入的所有参数.
kubectl delete $@
## @function: 强制删除一个pod
## $1: 目标Pod名称(必选)
## $2: 目标资源的所属空间, 如 -n namespace(可选)
function kkill0() {
## $@ 表示传入的所有参数.
kubectl delete pod --force --grace-period 0 $@
}
复制代码
注意:KUBECONFIG
环境变量值设置为自己的 config
文件即可,如:export KUBECONFIG=/root/th/.kube/config
2.5 查看与切换上下文
配置 KUBECONFIG
环境变量指定自定义的 config
文件后,便可以通过命令切换自定义的上下文,实现在不同的集群、命名空间工作的目的:
# 查看全部上下文
[root@k8smaster01 ~/th/.kube]# kubectl config get-contexts
# 在 `dev` 集群中的 `frontend` 命名空间中工作。
[root@k8smaster01 ~/th/.kube]# kubectl config --kubeconfig=root/th/.kube/config use-context dev-frontend
复制代码
通过 .bashrc
自定义脚本时,可以如下命令进行操作
# 查看全部上下文
[root@k8smaster01 ~]# kc
# 在 `dev` 集群中的 `frontend` 命名空间中工作。
[root@k8smaster01 ~]# ks dev-frontend
复制代码
参考
k8s官方文档: