DjangoはWebSSH操作Kubernetesポッドを達成します

免責事項:この記事はブロガーオリジナル記事です、続くBY-SAのCC 4.0を著作権契約、複製、元のソースのリンクと、この文を添付してください。
このリンク: https://blog.csdn.net/dengyu810/article/details/102661791

優れたフィードバックシステムは徐々に改善に基づいていて

記事では、我々は、セキュリティや多分岐頻繁にテストに対処する必要がありますし、Alodiシステムを開発した問題について説明し、Alodiはすぐにあなたがこの記事を見ることができる詳細な情報にアクセスするために、一時的なアドレスを生成するためのボタンを経由してテスト環境を構築することができます:Alodi:私はシステムを開発した秘密を維持するために、

システムがオンライン、SSHログインが急務コンソールになった後、WebSSH機能が、ダッシュボードのコンソールが、Alodiシステム、統合された意思決定WebSSH機能Alodi、最初と結合する方法はありませんKubernetes を見て 、最後に効果を実現すること

関係する技術

  • Kubernetesストリーム:データ受信の実行は、返されたリアルタイム・データ・ストリームを提供します
  • Djangoのチャンネル:長いデータはフロントエンドKubernetesに戻す送信しながら、先端Kubernetesに転送されるデータを受信し、接続を維持します
  • xterm.js:フロントエンドターミナルアセンブリ、アナログ表示端末用インターフェース

基本的なデータの流れは以下のとおりです。ユーザー - > xterm.js - >ジャンゴ・チャネル - > kubernetes流れ、その後、特定のコードの実装を見て

Kubernetesストリーム

Kubernetesはexec関数を実装する方法を提供し、それ自体をストリーム、データストリームは、次のようにのWebSocketは、非常に使いやすい使用することもでき、返されます。

from kubernetes import client, config
from kubernetes.stream import stream

class KubeApi:
    def __init__(self, namespace='alodi'):
        config.load_kube_config("/ops/coffee/kubeconfig.yaml")

        self.namespace = namespace

    def pod_exec(self, pod, container=""):
        api_instance = client.CoreV1Api()

        exec_command = [
            "/bin/sh",
            "-c",
            'TERM=xterm-256color; export TERM; [ -x /bin/bash ] '
            '&& ([ -x /usr/bin/script ] '
            '&& /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) '
            '|| exec /bin/sh']

        cont_stream = stream(api_instance.connect_get_namespaced_pod_exec,
                             name=pod,
                             namespace=self.namespace,
                             container=container,
                             command=exec_command,
                             stderr=True, stdin=True,
                             stdout=True, tty=True,
                             _preload_content=False
                             )

        return cont_stream

ここポッド名をすることができlist_namespaced_pod、次のコードとして取得します:

def get_deployment_pod(self, RAND):
    api_instance = client.CoreV1Api()

    try:
        r = api_instance.list_namespaced_pod(
            namespace=self.namespace,
            label_selector="app=%s" % RAND
        )

        return True, r
    except Exception as e:
        return False, 'Get Deployment: ' + str(e)
        
state, data = self.get_deployment_pod(RAND)
pod_name = data.items[0].metadata.name

list_namespaced_pod最初のものは、2つのパラメータを渡すここに記載されている名前空間の下にあるすべての詳細ポッドウィルnamespace必須であるが、我々は、名前空間の一覧を表示する必要がポッド、二表しlabel_selector名前空間の下に設定されたラベルによってフィルタリングすることができます非本質的に、私たちは、展開時に作成したので、ポッドは、それぞれユニークに追加されているapp=RANDので、ここで私たちがポッドに対応する項目をフィルタリングすることができ、ラベル

展開が複数のポッドに対応することができ、得られたが、data.itemsすべての情報ポッド、リストファイルが含まれている、名前が取得するために必要なポッドに対応していてもよいです

Djangoのチャンネル

導入Djangoのチャンネルの前に詳細に2件の記事が缶に最初のビューを理解していない、がありますDjangoはWebSocket--パートI達成するためにチャンネルを使用し、Djangoは次のWebSocket--達成するためのチャンネルを使用し、以下のように、コードの二つの最も重要な部分であります

ルーティングコード:

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter

from django.urls import path, re_path
from medivh.consumers import SSHConsumer

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter([
            re_path(r'^pod/(?P<name>\w+)', SSHConsumer),
        ])
    ),
})

一致するすべての定期的なpod始まりと呼ばれる呼ばれている接続のWebSocket SSHConsumer、消費者の処理、次のように消費者のコードは次のとおりです。

from channels.generic.websocket import WebsocketConsumer
from medivh.backends.kube import KubeApi
from threading import Thread

class K8SStreamThread(Thread):
    def __init__(self, websocket, container_stream):
        Thread.__init__(self)
        self.websocket = websocket
        self.stream = container_stream

    def run(self):
        while self.stream.is_open():
            if self.stream.peek_stdout():
                stdout = self.stream.read_stdout()
                self.websocket.send(stdout)

            if self.stream.peek_stderr():
                stderr = self.stream.read_stderr()
                self.websocket.send(stderr)
        else:
            self.websocket.close()


class SSHConsumer(WebsocketConsumer):
    def connect(self):
        self.name = self.scope["url_route"]["kwargs"]["name"]

        # kube exec
        self.stream = KubeApi().pod_exec(self.name)
        kub_stream = K8SStreamThread(self, self.stream)
        kub_stream.start()

        self.accept()

    def disconnect(self, close_code):
        self.stream.write_stdin('exit\r')

    def receive(self, text_data):
        self.stream.write_stdin(text_data)

WebSSHは、各接続が確立されたずっと後に簡単な接続用WebSocketとして見ることができる独立しており、他の接続とデータを共有しませんので、グループを使用する必要はありません

接続がを通して確立されるとself.scopeKubernetesのAPIを渡され、URL名に取得新しいデータの継続的なサイクルが発生した場合には、WebSocketのに送られた場合、また、新しいスレッドを再生します

データはKubernetesのAPIを書くのWebSocket直接受信されると、閉じたのWebSocketが送られexitKubernetesにコマンドを

フロントページ

メインのフロントエンドは、全体のコードは比較的単純である、xterm.jsを使用します

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Alodi | Pod Web SSH</title>
  <link rel="Shortcut Icon" href="/static/img/favicon.ico">
  
  <link href="/static/plugins/xterm/xterm.css" rel="stylesheet" type="text/css"/>
  <link href="/static/plugins/xterm/addons/fullscreen/fullscreen.css" rel="stylesheet" type="text/css"/>
</head>

<body>
  <div id="terminal"></div>
</body>

<script src="/static/plugins/xterm/xterm.js"></script>
<script src="/static/plugins/xterm/addons/fullscreen/fullscreen.js"></script>
<script>
  var term = new Terminal({cursorBlink: true});
  term.open(document.getElementById('terminal'));

  // xterm fullscreen config
  Terminal.applyAddon(fullscreen);
  term.toggleFullScreen(true);

  var socket = new WebSocket(
    'ws://' + window.location.host + '/pod/{{ name }}');

  socket.onopen = function () {
    term.on('data', function (data) {
        socket.send(data);
    });

    socket.onerror = function (event) {
      console.log('error:' + e);
    };

    socket.onmessage = function (event) {
      term.write(event.data);
    };

    socket.onclose = function (event) {
      term.write('\n\r\x1B[1;3;31msocket is already closed.\x1B[0m');
      // term.destroy();
    };
  };
</script>
</html>

term.openターミナルの初期化

term.onコンテンツは、バックエンドへのすべてのリアルタイム転送を入力します

導入はフルスクリーンを構成することができた後xterm.jsは、フルスクリーンプラグインを持っている、またはそれは、ターミナルウィンドウのページの一部であってもよいです

現在、まだ問題が発生すると、ウィンドウが解決されない、予備的な判断は、バックエンドのデータは、関連する情報を照会、Kubernetes決定を返さ、発見されたサイズを変更することはできませんkubectl追加することにより、コマンドをCOLUMNSし、LINESENVを設定します

#!/bin/sh
if [ "$1" = "" ]; then
  echo "Usage: kshell <pod>"
  exit 1
fi
COLUMNS=`tput cols`
LINES=`tput lines`
TERM=xterm
kubectl exec -i -t $1 env COLUMNS=$COLUMNS LINES=$LINES TERM=$TERM bash

しかし、ストリームKubernetes PythonのAPIは、あなたが知っていれば、私の悩みを教えて、場所を見つけるように構成されていません


関連記事推奨読書:

おすすめ

転載: blog.csdn.net/dengyu810/article/details/102661791