配置对多个Kubernetes集群的访问

配置对多集群的访问

一、背景

​ 当使用 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.crtclient.crtclient.key 等字符串提取出来, 存到 ca.crtclient.crtclient.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官方文档:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享