kubernetes pod exec接口调用

正文

通常生产环境上因为网络安全策略,大多数端口是不能为集群外部访问的。多个集群之间通常都是经过k8s的ApiServer组件提供的接口通讯,如https://192.168.1.101:6443。因此在作云平台时,集群管理平台(雅称:观云台)须要操做其余集群的资源对象时,必然也得经过ApiServer。前端

k8s负载均衡器组件ingress-nginx-controller中集成的nginx,当集群ingress、tcp configmaps、udp configmaps等资源发生变化时,ingress-nginx-controller会根据这些资源最新配置,并根据提早设定好的nginx.tmpl模板(nginx配置文件nginx.conf由该模板生成)生成最新的nginx.conf配置,并自动进行nginx -s reload操做。最近作的一个需求,部分负载均衡器能够在页面上由运维人员自动配置,经过nginx的server、map配置。根据请求头的不一样将流量分配到不一样的服务。能够参考nginx map配置根据请求头不一样分配流量到不一样后端服务java

配置后须要在观云台上手动reload负载均衡器,以使配置生效。这就涉及到从观云台去操做多集群的负载均衡器。python

经过修改ingress-nginx-controller源码提供接口reload方案,因为网络规则限制确定行不通;只有6443端口能够走。能不能像操做集群内资源同样去操做其余集群资源?nginx

一、kubectl命令其实对应的就是调用apiserver去操做资源,在集群内咱们都知道能够用如下命令:git

kubectl exec -ti ingress-nginx-abab121 -nkube-system -- nginx -s reload复制代码

那么从A集群去操做B集群,假设B的ApiServer地址为:https://192.168.1.101:6443,Bearer token为212k1jj1jak12k1kjaeeba,则命令以下:github

kubectl exec -ti ingress-nginx-abab121 -nkube-system --server=https://192.168.1.101:6443 --token=212k1jj1jak12k1kjaeeba --insecure-skip-tls-verify=true -- nginx -s reload复制代码

经过查看kubelet的源代码,能够发现$GOPATHsrck8s.iokubernetespkgkubeletserverserver.go的InstallDebuggingHandlers方法中注册了exec、attach、portForward等接口,同时kubelet的内部接口经过api server对外提供服务,因此对API server的这些接口调用,能够直接访问到kubelet,即client -->> API server --> kubeletweb

二、能够用curl命令调用以下:面试

curl -k \
     -H "Connection: Upgrade" \
     -H "Authorization: Bearer 212k1jj1jak12k1kjaeeba" \
     -H "Upgrade: websocket" \
     -H "Sec-Websocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
     -H "Sec-Websocket-Version: 13" \
"https://192.168.26.19:6443/api/v1/namespaces/liano/pods/nginx/exec?command=ls&stdin=true&stout=true&tty=true"复制代码

image.png

三、kubernetes开源社区维护了各类语言版本与k8s apiserver交互的client库,好比java库地址以下:https://github.com/kubernetes-client/java其中提供了调用pod的exec接口代码示例:https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/ExecExample.java须要先依赖:spring

<dependency>
    <groupId>io.kubernetes</groupId>
    <artifactId>client-java</artifactId>
    <version>4.0.0</version>
    <scope>compile</scope>
</dependency>复制代码

而后根据apiserver地址和Bearer token构建client,到访问pod exec接口进行nginx -s reload代码示例以下:编程

package com.liano.api.test;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.Exec;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.credentials.AccessTokenAuthentication;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

/**
 * @program: k8s-mars
 * @description: ExecKubelet
 * @author: liano
 * @create: 2019-03-06 15:10
 **/

public class ExecKubeletDemo {
    public static void main(String[] args) throws IOException, ApiException, InterruptedException {
        new ExecKubeletDemo().execNginxReload();
    }

    private void execNginxReload() throws InterruptedException, ApiException, IOException {

        //apiServer地址和Bbearer token方式认证
        ApiClient client = new ClientBuilder().setBasePath("https://10.10.101.60:6443").setVerifyingSsl(false)
                .setAuthentication(new AccessTokenAuthentication("33095a7b86a7a3462ea45a1410624b")).build();
//        client.setDebugging(true);

        Configuration.setDefaultApiClient(client);

        JSONObject res = process("nginx-97ccd777-xk9pw", "kube-system");
        System.out.println(JSONObject.toJSONString(res));
    }

    private JSONObject process(String podName, String namespace) throws IOException, ApiException, InterruptedException {
        Exec exec = new Exec();
        // final Process proc = exec.exec("default", "nginx-4217019353-k5sn9", new String[]
        //   {"sh", "-c", "echo foo"}, true, tty);
        String[] commands = new String[]{"nginx", "-s", "reload"};
        final Process proc = exec.exec(namespace, podName, commands, true, true);

        JSONObject res = new JSONObject();

        Thread out = new Thread(
                new Runnable() {
                    public void run() {
                        String copy = copy(proc.getInputStream());
                        res.put("data", copy);
                    }
                });
        out.start();

        proc.waitFor();

        out.join();

        proc.destroy();

        if (proc.exitValue() != 0) {
            res.put("success", false);
        } else {
            res.put("success", true);
        }

        return res;
    }
    
    private String copy(InputStream from) {
        Preconditions.checkNotNull(from);
        BufferedReader in = null;
        Reader reader = null;
        StringBuilder sb = new StringBuilder();
        try {
            reader = new InputStreamReader(from);
            in = new BufferedReader(reader);
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            try {
                if (from != null) {
                    from.close();
                }

                if (reader != null) {
                    reader.close();
                }

                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
                System.out.println(e);
            }
        }

        return sb.toString();
    }
}复制代码

从io.kubernetes.client.Exec源码中能够看到,需求经过 HTTP/1.1 协议的101状态码进行握手进一步创建websocket。websocket是一种在单个TCP链接上进行全双工通讯的协议, 是独立的、建立在 TCP 上的协议。为了建立Websocket链接,须要经过客户端发出请求,以后服务器进行回应,这个过程一般称为“握手”(handshaking)。

一个典型的Websocket握手请求以下:

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13复制代码

服务器回应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/复制代码

字段说明

Connection必须设置Upgrade,表示客户端但愿链接升级。
Upgrade字段必须设置Websocket,表示但愿升级到Websocket协议。
Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,而后计算SHA-1摘要,以后进行BASE-64编码,将结果作为“Sec-WebSocket-Accept”头的值,返回给客户端。如此操做,能够尽可能避免普通HTTP请求被误认为Websocket协议。
Sec-WebSocket-Version 表示支持的Websocket版本。RFC6455要求使用的版本是13,以前草案的版本均应当弃用。
Origin字段是可选的,一般用来表示在浏览器中发起此Websocket链接所在的页面,相似于Referer。可是,与Referer不一样的是,Origin只包含了协议和主机名称。
其余一些定义在HTTP协议中的字段,如Cookie等,也能够在Websocket中使用。复制代码

本公众号免费提供csdn下载服务,海量IT学习资源,若是你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时咱们组建了一个技术交流群,里面有不少大佬,会不定时分享技术文章,若是你想来一块儿学习提升,能够公众号后台回复【2】,免费邀请加技术交流群互相学习提升,会不按期分享编程IT相关资源。

扫码关注,精彩内容第一时间推给你

image

相关文章
相关标签/搜索