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

相關文章
相關標籤/搜索