通常生產環境上因爲網絡安全策略,大多數端口是不能爲集羣外部訪問的。多個集羣之間通常都是經過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"複製代碼
三、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相關資源。
掃碼關注,精彩內容第一時間推給你