admin管理员组文章数量:1794759
TKE集群如何在pod内执行kubectl访问apiserver及登录node节点
腾讯云上创建一个TKE集群,一般都是需要开启集群的内网或者公网访问,才能kubectl访问集群apiserver,如果要登录node节点,需要ssh工具去登录,这种一般要有节点秘钥或者密码,但是一般只有运维才有节点登录方式。 下面我们来说说如何创建一个pod,来访问集群的apiserver,并登录node节点,下面我说的方式,是不需要节点登录密码或者秘钥,也不需要集群开启内网或者公网访问。
1. 前提条件
1. 首先你在腾讯云上有tke集群的cam权限和rbac权限(需要有写权限),能控制台访问集群和在集群内创建资源。 2. API秘钥管理页面获取到你子账号的API密钥,也就是SecretId,和SecretKey,并且有tke接口DescribeClusterSecurity访问权限。
2. 原理说明
集群不开内网或者公网访问,然后通过kubectl访问到apiserver,是基于token和集群apiserver的clusterip实现的,现在集群默认不提供token,我们可以通过DescribeClusterSecurity接口获取,Password字段就是对应的token,CertificationAuthority对应的是集群CA证书。
tke集群创建后,在default下默认有个kubernetes,这里有个clusterip,集群内可以通过这个访问到托管集群的apiserver,这个ip可以在集群内容器环境变量KUBERNETES_PORT_443_TCP获取。
通过接口获取的CA证书,token以及集群apiserver的clusterip,可以生成kubeconfig用于访问集群。
pod内直接登录node节点,则是通过kubectl-node-shell,具体可以参考文档
3. 镜像构建
3.1 镜像构建Dockerfile
代码语言:dockerfile复制FROM alpine:latest
COPY ./ /root
RUN sed -i 's/dl-cdn.alpinelinux/mirrors.ustc.edu/g' /etc/apk/repositories && \
apk add --no-cache redis mysql-client vim tcpdump curl bind-tools mtr nmap-ncat busybox-extras bash bash-doc bash-completion python3 py3-pip && \
pip3 install tencentcloud-sdk-python-tke --break-system-packages && \
curl -LO .22.5/bin/linux/amd64/kubectl && \
chmod +x ./kubectl && \
mv ./kubectl /usr/local/bin/kubectl && \
mv /root/kubectl-node_shell /usr/local/bin/
CMD ["sh", "-c", "/root/start.sh"]
3.2 启动脚本start.sh
代码语言:shell复制#!/bin/bash
python /root/get_cluster_token_and_ca.py
TOKEN=`cat /root/token`
apiserver_ip=`echo $KUBERNETES_PORT_443_TCP | awk -F'[/:]' '{print $4}'`
APISRRVICE=https://${apiserver_ip}
kubectl config set-cluster ${ClusterId} --certificate-authority='/root/ca.crt' --embed-certs=true --server=${APISRRVICE} --kubeconfig=${ClusterId}.kubeconfig
kubectl config set-credentials ${ClusterId} --token=${TOKEN} --kubeconfig=${ClusterId}.kubeconfig
kubectl config set-context ${ClusterId}-default --cluster=${ClusterId} --user=${ClusterId} --kubeconfig=${ClusterId}.kubeconfig
kubectl config use-context ${ClusterId}-default --kubeconfig=${ClusterId}.kubeconfig
mkdir -p /root/.kube
mv ${ClusterId}.kubeconfig /root/.kube/config
tail -f /dev/null
3.3 调云api接口脚本get_cluster_token_and_ca.py
代码语言:python代码运行次数:0运行复制import json
import os
import types
from tencentcloudmon import credential
from tencentcloudmon.profile.client_profile import ClientProfile
from tencentcloudmon.profile.http_profile import HttpProfile
from tencentcloudmon.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.tke.v20180525 import tke_client, models
try:
SecretId = os.getenv('SecretId')
SecretKey = os.getenv('SecretKey')
clusterId = os.getenv('ClusterId')
cred = credential.Credential(SecretId, SecretKey)
# 实例化一个http选项,可选的,没有特殊需求可以跳过
httpProfile = HttpProfile()
httpProfile.endpoint = "tke.tencentcloudapi"
# 实例化一个client选项,可选的,没有特殊需求可以跳过
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
# 实例化要请求产品的client对象,clientProfile是可选的
client = tke_client.TkeClient(cred, "ap-shanghai", clientProfile)
# 实例化一个请求对象,每个接口都会对应一个request对象
req = models.DescribeClusterSecurityRequest()
params = {
"ClusterId": clusterId
}
req.from_json_string(json.dumps(params))
# 返回的resp是一个DescribeClusterSecurityResponse的实例,与请求对象对应
resp = client.DescribeClusterSecurity(req)
# 输出json格式的字符串回包
res = json.loads(resp.to_json_string())
token=res["Password"]
cacert=res["CertificationAuthority"]
with open("/root/ca.crt", 'w', encoding='utf-8') as file:
file.write(cacert)
with open("/root/token", 'w', encoding='utf-8') as file:
file.write(token)
except TencentCloudSDKException as err:
print(err)
3.4 kubectl-node_shell脚本
这里修改了nsenter容器的reqeust资源值,也就是container_cpu和container_memory变量的值,都改成了0
代码语言:shell复制#!/usr/bin/env sh
set -e
kubectl=kubectl
version=1.10.0
generator=""
node=""
nodefaultctx=0
nodefaultns=0
container_cpu="${KUBECTL_NODE_SHELL_POD_CPU:-0m}"
container_memory="${KUBECTL_NODE_SHELL_POD_MEMORY:-0Mi}"
volumes="[]"
volume_mounts="[]"
x_mode=0
labels="${KUBECTL_NODE_SHELL_LABELS}"
pod_running_timeout="${KUBECTL_NODE_SHELL_POD_RUNNING_TIMEOUT:-1m}"
if [ -t 0 ]; then
tty=true
else
tty=false
fi
while [ $# -gt 0 ]; do
key="$1"
case $key in
-v | --version)
echo "kubectl-node-shell $version"
exit 0
;;
--context)
nodefaultctx=1
kubectl="$kubectl --context $2"
shift
shift
;;
--kubecontext=*)
nodefaultctx=1
kubectl="$kubectl --context=${key##*=}"
shift
;;
--kubeconfig)
kubectl="$kubectl --kubeconfig $2"
shift
shift
;;
--kubeconfig=*)
kubectl="$kubectl --kubeconfig=${key##*=}"
shift
;;
-n | --namespace)
nodefaultns=1
kubectl="$kubectl --namespace $2"
shift
shift
;;
--namespace=*)
nodefaultns=1
kubectl="$kubectl --namespace=${key##*=}"
shift
;;
-x)
x_mode=1
volumes='[{"hostPath":{"path":"/","type":""},"name":"host-root"}]'
volume_mounts='[{"mountPath":"/host","name":"host-root"}]'
shift
;;
--)
shift
break
;;
*)
if [ -z "$node" ]; then
node="${1#node/}"
shift
else
echo "exactly one node required"
exit 1
fi
;;
esac
done
if [ -z "$node" ]; then
echo "Please specify node name"
exit 1
fi
if [ -z "$KUBERNETES_PORT" ]; then
# Set the default context and namespace to avoid situations where the user switch them during the build process
[ "$nodefaultctx" = 1 ] || kubectl="$kubectl --context=$(${kubectl} config current-context)"
[ "$nodefaultns" = 1 ] || kubectl="$kubectl --namespace=$(${kubectl} config view --minify --output 'jsonpath={.contexts..namespace}')"
fi
# Check the node and retrieve the node OS label
os="$($kubectl get node $node -o jsonpath="{.metadata.labels.kubernetes\.io/os}" || exit 1)"
# Set pod configuration per operating system
if [ "$os" = "windows" ]; then
image="${KUBECTL_NODE_SHELL_IMAGE_WINDOWS:-mcr.microsoft/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0}"
name="pwsh"
pod="${name}-$(env LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 6)"
cmd_start='"cmd.exe", "/c", "powershell.exe", "-nol"'
cmd_arg_prefix=', "-Command"'
cmd_default=''
security_context='{"privileged":true,"windowsOptions":{"hostProcess":true,"runAsUserName":"NT AUTHORITY\\SYSTEM"}}'
else # If the OS isn't windows, assume linux
image="${KUBECTL_NODE_SHELL_IMAGE:-docker.io/library/alpine}"
name="nsenter"
pod="${name}-$(env LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 6)"
cmd_start='"nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid"'
cmd_arg_prefix=', "--"'
cmd_default=', "bash", "-l"'
security_context='{"privileged":true}'
fi
# Build the container command
if [ $# -gt 0 ]; then
if [ "$x_mode" -eq 1 ]; then
cmd='['
else
cmd="[ $cmd_start $cmd_arg_prefix,"
fi
c=""
while [ $# -gt 0 ]; do
cmd="${cmd}${c} \"$(echo "$1" | \
awk '{gsub(/["\\]/,"\\\\&");gsub(/\x1b/,"\\u001b");printf "%s",last;last=$0"\\n"} END{print $0}' \
)\""
c=,
shift
done
cmd="$cmd ]"
else
if [ "$x_mode" = 1 ]; then
cmd='null'
else
cmd="[ $cmd_start $cmd_default ]"
fi
fi
# test if resource specification is required
resources_json='"resources": {
"limits": { "cpu": "'${container_cpu}'", "memory": "'${container_memory}'" },
"requests": { "cpu": "'${container_cpu}'", "memory": "'${container_memory}'" }
}'
$kubectl run --image "$image" "$pod" --dry-run=server 2>&1 | grep -q 'failed quota' || resources_json='"resources": {}'
overrides="$(
cat <<EOT
{
"spec": {
"nodeName": "$node",
"hostPID": true,
"hostNetwork": true,
"containers": [
{
"securityContext": $security_context,
"image": "$image",
"name": "$name",
"stdin": true,
"stdinOnce": true,
"tty": $tty,
"command": $cmd,
$resources_json,
"volumeMounts": $volume_mounts
}
],
"tolerations": [
{ "key": "CriticalAddonsOnly", "operator": "Exists" },
{ "effect": "NoExecute", "operator": "Exists" }
],
"volumes": $volumes
}
}
EOT
)"
# Support Kubectl <1.18
m=$(kubectl version --client -o yaml | awk -F'[ :"]+' '$2 == "minor" {print $3+0}')
if [ "$m" -lt 18 ]; then
generator="--generator=run-pod/v1"
fi
trap "EC=\$?; $kubectl delete pod --wait=false $pod >&2 || true; exit \$EC" EXIT INT TERM
echo "spawning \"$pod\" on \"$node\"" >&2
$kubectl run --image "$image" --restart=Never --overrides="$overrides" --labels="$labels" --pod-running-timeout="$pod_running_timeout" $([ "$tty" = true ] && echo -t) -i "$pod" $generator
3.5 构建目录
将文件按照名称一一复制到构建目录,目录结构如下
代码语言:txt复制total 20
-rw-r--r-- 1 root root 584 Oct 4 13:07 Dockerfile
-rw-r--r-- 1 root root 1749 Oct 4 15:08 get_cluster_token_and_ca.py
-rwxr-xr-x 1 root root 4908 Oct 4 10:25 kubectl-node_shell
-rwxr-xr-x 1 root root 749 Oct 4 15:37 start.sh
3.6 镜像构建
在构建目录,执行镜像构建命令,构建推送镜像,可以用我构建好的镜像,也可以自行构建镜像
代码语言:txt复制docker build -t ccrs.tencentyun/niewx-k8s/tke-kubectl-tool:latest .
docker push ccrs.tencentyun/niewx-k8s/tke-kubectl-tool:latest
4. 部署工作负载
下面是部署的yaml,默认会创建一个configmap和deployment。
代码语言:yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: kubectl-demo
qcloud-app: kubectl-demo
name: kubectl-demo
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kubectl-demo
qcloud-app: kubectl-demo
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
k8s-app: kubectl-demo
qcloud-app: kubectl-demo
spec:
affinity: {}
containers:
- envFrom:
- configMapRef:
name: env
image: ccrs.tencentyun/niewx-k8s/tke-kubectl-tool:latest
imagePullPolicy: Always
name: demo
resources:
limits:
cpu: "0"
memory: "0"
requests:
cpu: "0"
memory: "0"
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: qcloudregistrykey
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: v1
data:
ClusterId: cls-xxxxx
SecretId: AKxxxx
SecretKey: 9Wxxxx
kind: ConfigMap
metadata:
name: env
configmap变量说明:
- ClusterId:当前需要部署的tke集群id
- SecretId:api访问秘钥的SecretId
- SecretKey:api访问秘钥的SecretKey
5. 测试访问集群并登录node
将第四步的yaml,控制台创建后,然后登录对应的容器,kubectl访问和登录node
pod起来后,登录容器,kubectl访问apiserver正常,登录节点也正常,说明配置正常,后续我们就不需要给集群apiserver开启内网或者公网访问来执行kubectl了,也可以直接不通过密码或者秘钥登录节点了。
本文标签: TKE集群如何在pod内执行kubectl访问apiserver及登录node节点
版权声明:本文标题:TKE集群如何在pod内执行kubectl访问apiserver及登录node节点 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1755022322a1709531.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论