欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

云vscode搭建之使用容器化部署的方法

 更新時間:2022年09月05日 10:42:18   作者:CoreDump丶  
隨著容器化的發(fā)展,現(xiàn)在涌現(xiàn)出了很多云IDE,比如騰訊的Cloud?Studio,但是其也是基于Code-Server進行開發(fā)部署的,用了它的云IDE后,我便產(chǎn)生出了自己部署一個這樣的云IDE的想法,這篇文章主要介紹了云vscode搭建使用容器化部署,需要的朋友可以參考下

Vscode作為一個輕量級的IDE,其支持豐富的插件,而通過這些插件我們就可以實現(xiàn)在Vscode中寫任何語言的代碼。Code-Server是Vscode的網(wǎng)頁版,啟動Code-Server之后我們就可以在瀏覽器中打開vscode來愉快的編寫代碼了。這種方式非常適合我們做linux編程。使用C/C++的時候,在windows上編寫的代碼在linux上可能跑不了,而且安裝linux圖形界面,然后在圖像界面中使用vscode又很麻煩。當然也可以使用vscode的遠程開發(fā)。但是我認為啟動code-server來在瀏覽器上使用vscode也是非常方便的。

隨著容器化的發(fā)展,現(xiàn)在涌現(xiàn)出了很多云IDE,比如騰訊的Cloud Studio,但是其也是基于Code-Server進行開發(fā)部署的,用了它的云IDE后,我便產(chǎn)生出了自己部署一個這樣的云IDE的想法。

1、Code-Server下載部署

1.1 Code-Server下載

下載地址:https://github.com/coder/code-server/releases/

在上面的網(wǎng)址中下載code-server,并將其傳輸?shù)絣inux服務(wù)器上。

也可以在linux服務(wù)器中直接使用命令來下載:

wget https://github.com/coder/code-server/releases/download/v4.6.1/code-server-4.6.1-linux-amd64.tar.gz

1.2 Code-Server部署

1.解壓tar.gz文件:

 tar -zxvf code-server-4.6.1-linux-amd64.tar.gz

2.進入code-server目錄:

cd code-server-4.6.1-linux-amd64

3.設(shè)置密碼到環(huán)境變量中

export PASSWORD="xxxx"

4.啟動code-server

./code-server --port 8888 --host 0.0.0.0 --auth password 

在瀏覽器中輸入ip:8888來訪問如下:

后臺運行的方式:

nohup ./code-server --port 8888 --host 0.0.0.0 --auth password &

1.3 Docker部署Code-Server

接下來將介紹使用Docker的方式來部署Code-Server:

下面的Dockerfile創(chuàng)建了一個帶有Golang開發(fā)環(huán)境的容器,然后在容器中運行Code-Server,將Dockerfile放在跟code-server-4.4.0-linux-amd64.tar.gz同目錄。

1.創(chuàng)建名為Dockerfile的文件(Dockerfile要跟code-server的tar.gz文件在同一目錄中),將下面內(nèi)容復制進去

FROM golang

WORKDIR /workspace

RUN cp /usr/local/go/bin/* /usr/local/bin

COPY code-server-4.4.0-linux-amd64.tar.gz .
RUN tar zxvf code-server-4.4.0-linux-amd64.tar.gz

ENV GO111MODULE on 
ENV GOPROXY https://goproxy.cn

ENV PASSWORD abc123

WORKDIR /workspace/code-server-4.4.0-linux-amd64
EXPOSE 9999
CMD ["./code-server", "--port", "9999", "--host", "0.0.0.0", "--auth", "password"]

2.然后執(zhí)行命令構(gòu)建Docker鏡像:

docker build -t code-server .

3.運行容器

docker run -d --name code-server -p 9999:9999 code-server

2. 一個小問題

下面的內(nèi)容針對Docker部署的Code-Server。

想象這樣一個場景,我們開發(fā)了一個類似Cloud Studio的云IDE,每啟動一個工作空間我們就通過Docker或者Kubernetes來創(chuàng)建一個容器,然后在容器中部署一個Code-Server,最后通過將端口暴露出去給用戶使用。

云IDE使用起來很方便,打開和銷毀的很迅速,即開即用。用戶使用Golang在云IDE中寫了一個http服務(wù)器,想要在他電腦的瀏覽器上訪問,卻發(fā)現(xiàn)訪問不了。那么為什么Code-Server的端口就可以訪問,其它端口無法訪問呢。因為我們在啟動容器的時候就已經(jīng)預想到要訪問這個端口,然后將端口暴露出去了,也就是建立了端口映射。在容器中新啟動的端口并沒有建立映射,因此只能在服務(wù)器內(nèi)部訪問,而不能在用戶電腦上訪問。

那么如何讓用戶也可以訪問到呢,我們可以在主機上部署一個代理服務(wù)器,用戶訪問這個代理服務(wù)器,然后轉(zhuǎn)發(fā)請求到容器中,再將響應(yīng)轉(zhuǎn)發(fā)給用戶。

那么如何發(fā)現(xiàn)用戶啟動服務(wù)器監(jiān)聽了哪個端口呢,首先我能想到的就是啟動一個程序每隔一段時間查詢一下是否有新的端口被監(jiān)聽。獲取端口信息可以使用netstat命令或者lsof命令,在此我選擇了netstat,就有了下面的一個程序:

2.1 端口監(jiān)聽

這個程序會每隔一秒獲取一下有哪些端口處于LISTEN狀態(tài),然后對比上一次的狀態(tài),看是否有新的端口被監(jiān)聽。當我們監(jiān)聽了新的80端口后,就會輸出:Find new port: 80

package main

import (
	"bytes"
	"fmt"
	"os/exec"
	"strconv"
	"time"
)

func main() {
	listener := NewPortListener()
	pc := listener.GetPortChan()
	go listener.FindNewPortLoop()
	for {
		port := <-pc
		fmt.Println("Find new port:", port)
	}
}

type PortListener struct {
	portChan chan uint16
}

func NewPortListener() *PortListener {
	return &PortListener{
		portChan: make(chan uint16, 1),
	}
}

func (p *PortListener) GetPortChan() <-chan uint16 {
	return p.portChan
}

func (p *PortListener) FindNewPortLoop() {
	ports := p.getListeningPorts()          // 程序啟動后先獲取一次處于Listen狀態(tài)的端口
	set := map[uint16]struct{}{}
	for _, port := range ports {
		set[port] = struct{}{}
	}

	for {                                   // 然后每隔一秒獲取一次,并與前一次的信息進行對比,查找是否啟動了新的端口
		tmpSet := map[uint16]struct{}{}     
		ports = p.getListeningPorts()
		for _, port := range ports {
			if _, ok := set[port]; !ok {
				p.portChan <- port
			}
			tmpSet[port] = struct{}{}
		}
		set = tmpSet
		time.Sleep(time.Second * 3)
	}
}

func (p *PortListener) getListeningPorts() []uint16 {
	cmd := exec.Command("netstat", "-ntlp")          // 運行netstat命令獲取處于Listen狀態(tài)的端口信息
	res, err := cmd.CombinedOutput()                 // 獲取結(jié)果 
	fmt.Println(string(res))
	if err != nil {
		fmt.Println("Execute netstat failed")
		return nil
	}

	return p.parsePort(res)                         // 對結(jié)果進行解析
}

func (p *PortListener) parsePort(msg []byte) []uint16 {       // 解析出處于LISTEN狀態(tài)的端口,只要端口號
	idx := bytes.Index(msg, []byte("tcp"))
	colums := bytes.Split(msg[idx:], []byte("\n"))
	res := make([]uint16, 0, len(colums)-1)
	for i := 0; i < len(colums)-1; i++ {
		item := p.findThirdItem(colums[i])
		if item != nil {
			m := bytes.IndexByte(item, ':') + 1
			for item[m] == ':' {
				m++
			}
			p, err := strconv.Atoi(string(item[m:]))
			if err == nil {
				res = append(res, uint16(p))
			} else {
				fmt.Println(err)
			}
		}
	}

	return res
}

func (p *PortListener) findThirdItem(colum []byte) []byte {
	count := 0
	for i := 0; i < len(colum); {
		if colum[i] == ' ' {
			for colum[i] == ' ' {
				i++
			}
			count++
			continue
		}
		if count == 3 {
			start := i
			for colum[i] != ' ' {
				i++
			}
			return colum[start:i]
		}
		i++
	}

	return nil
}

2.2 使用VS-Code插件

但是上面的程序也無法通知到用戶,在使用Cloud Studio的時候,啟動了新的端口,這個云IDE就會提醒發(fā)現(xiàn)了新的端口,是否要在瀏覽器中訪問。因此我就想到了實現(xiàn)這樣一個插件,因此下面部分就是實現(xiàn)一個vscode的插件來發(fā)現(xiàn)是否有新的端口被監(jiān)聽了,然后提醒用戶是否在瀏覽器中訪問。

下面只是簡單介紹,想要了解vscode插件的詳細開發(fā)過程的自行搜索。

1.首先安裝yeoman腳手架工具,以及官方提供的腳手架工具:

npm install -g yo generator-code

2.創(chuàng)建項目,選擇要創(chuàng)建的項目以及其它信息

yo code

3.創(chuàng)建完成后,就可以編寫插件了

// extension.js
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed

/**
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with  registerCommand
	// The commandId parameter must match the command field in package.json
	let disposable = vscode.commands.registerCommand('port-finder.helloWorld', function () {
		// The code you place here will be executed every time your command is executed

		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World from port_finder!');
	});

	context.subscriptions.push(disposable);

	initGetPorts()
}

var s = new Set() 

function initGetPorts() {
    getListeningPorts(function(ports) {
        ports.forEach(p => {
            s.add(p)
        })

        setInterval(function() {        // 設(shè)置定時器,每隔一秒獲取一次
            listenPortChange()
        }, 1000)
    })
}

function listenPortChange() {
    // 獲取處于LISTEN狀態(tài)的端口
    getListeningPorts(function(ports) {
        var tmpSet = new Set()     
        ports.forEach(p => {
            if (!s.has(p)) {
                // 發(fā)現(xiàn)新的端口被監(jiān)聽就提醒用戶是否在瀏覽器中打開
                vscode.window.showInformationMessage("發(fā)現(xiàn)新開啟的端口:" + p + ",是否在瀏覽器中訪問?", "是", "否", "不再提示")
                .then(result=> {
                    if (result === "是") {
                        // 在瀏覽器中打開來訪問代理服務(wù)器,后面帶上端口信息,以便代理服務(wù)器知道訪問容器的哪個端口
                        vscode.env.openExternal(vscode.Uri.parse(`http://192.168.44.100/proxy/` + p))
                    } 
                })
            }
            tmpSet.add(p)
        })
        s = tmpSet
    })
}

function getListeningPorts(callback) {
    var exec = require('child_process').exec;
    
    exec('netstat -nlt', function(error, stdout, stderr){
        if(error) {
            console.error('error: ' + error);
            return;
        }
        
        var ports = parsePort(stdout)
        callback(ports)
    })
}

function parsePort(msg) {
    var idx = msg.indexOf("tcp")
    msg = msg.slice(idx, msg.length)
    var colums = msg.split("\n")
    var ret = new Array()
    colums = colums.slice(0, colums.length - 1)
    colums.forEach(element => {
        
        var port = findPort(element)
        if (port != -1) {
            ret.push(port)
        }
    });

    return ret;
}

function findPort(colum) {
    var idx = colum.indexOf(':')
    var first = colum.slice(0, idx)
    while (colum[idx] == ':') {
        idx++
    }
    var second = colum.slice(idx, colum.length)
    var fidx = first.lastIndexOf(' ')
    var sidx = second.indexOf(' ')
    var ip = first.slice(fidx + 1, first.length)
    var port = second.slice(0, sidx)

    if (ip == "127.0.0.1") {
        return -1
    } else {
        return Number(port)
    }
}

// this method is called when your extension is deactivated
function deactivate() {}

module.exports = {
	activate,
	deactivate
}

4.然后構(gòu)建項目,首先安裝vsce庫,再打包

npm i -g vsce
vsce package

5.打包后生成了vsix文件,將vsix文件上傳到服務(wù)器,然后再拷貝到docker容器中

# docker拷貝命令
docker cp 主機文件名 容器ID或容器名:/容器內(nèi)路徑

然后在瀏覽器中的vscode中選擇vsix文件來安裝插件

安裝完之后,我們的插件在vscode打開后就會啟動,然后每隔一秒查詢一個端口情況。

測試

接下來,測試一下插件:

在vscode中寫了一個http服務(wù)器,然后啟動這個服務(wù)器,看插件是否能發(fā)現(xiàn)這個端口被監(jiān)聽了

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type KK struct {
	Name          string `json:"name"`
	Prictice_time string `json:"prictice time"`
	Hobby         string `json:"hobby"`
}

func main() {
	engine := gin.Default()
	engine.GET("/", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, &KK{
			Name:          "kunkun",
			Prictice_time: "two and a half years",
			Hobby:         "sing jump and rap",
		})
	})

	engine.Run(":8080")
}

運行http服務(wù)器:

go run main.go

可以看到,它彈出了提示,提示我們是否在瀏覽器中打開

但是現(xiàn)在在瀏覽器中打開是訪問不了容器中的http服務(wù)器的,因為端口沒有被映射到主機端口上。

2.3 代理服務(wù)器實現(xiàn)

在此,為了驗證我的想法是否能成功,只是實現(xiàn)了一個簡單的代理服務(wù)器,它將請求轉(zhuǎn)發(fā)的容器中,然后再轉(zhuǎn)發(fā)容器中服務(wù)器的響應(yīng)。(因為代理服務(wù)器是直接運行在主機上的,因此可以通過容器IP+端口來訪問)

代碼如下:

package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	engine := gin.Default()
	engine.GET("/proxy/*all", func(ctx *gin.Context) {
		all := ctx.Param("all")                    // 獲取/proxy后面的參數(shù) 
		if len(all) <= 0 {
			ctx.Status(http.StatusBadRequest)
			return
		}
		all = all[1:]                             // 丟棄第一個'/'
		idx := strings.Index(all, "/")
		var url string
		if idx < 0 {                              // 只有端口
			url = fmt.Sprintf("http://172.17.0.3:%s", all)
		} else {                                 // 有端口和其它訪問路徑
			port := all[:idx]
			url = fmt.Sprintf("http://172.17.0.3:%s%s", port, all[idx:])
		}
		resp, err := http.Get(url)               // 訪問容器中的服務(wù)器
		if err != nil {
			ctx.Status(http.StatusBadRequest)
			return
		}
		io.Copy(ctx.Writer, resp.Body)            // 轉(zhuǎn)發(fā)響應(yīng)
	})

	engine.Run(":80")
}

在主機服務(wù)器上運行代理服務(wù)器,不要使用容器來啟動:

go build 
nohup ./porxy_server &           # 后臺運行

然后我們再啟動瀏覽器vscode中的服務(wù)器看是否可以訪問到:

選擇"是",然后在新彈出的窗口中就可以訪問到容器中的服務(wù)了:

這里實現(xiàn)的只是一個非常簡易的版本,只是提供了一個這樣的思路。如何要實現(xiàn)一個類似Cloud Studio的云IDE要考慮的還要更多。
最終效果如下:

到此這篇關(guān)于云vscode搭建使用容器化部署的文章就介紹到這了,更多相關(guān)云vscode搭建內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • git pull每次都要輸入用戶名和密碼的解決辦法

    git pull每次都要輸入用戶名和密碼的解決辦法

    本文主要介紹了git pull每次都要輸入用戶名和密碼的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • 在Linux下搭建Git服務(wù)器的方法詳解

    在Linux下搭建Git服務(wù)器的方法詳解

    雖然用Git的人不多,但是git不僅僅是svn等版本控制系統(tǒng)的替換工具,它自己強大的功能,穩(wěn)定的性能,方便快捷等優(yōu)點自然不需多說,不了解的人自行去網(wǎng)上查看。本文將會詳細介紹在Linux下搭建Git服務(wù)器的方法,有需要的朋友們可以參考借鑒。
    2016-09-09
  • VSCode 格式化縮進代碼的實現(xiàn)

    VSCode 格式化縮進代碼的實現(xiàn)

    這篇文章主要介紹了VSCode 格式化縮進代碼的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Jar包一鍵重啟的Shell腳本及新服務(wù)器部署的一些經(jīng)驗分享

    Jar包一鍵重啟的Shell腳本及新服務(wù)器部署的一些經(jīng)驗分享

    這篇文章主要介紹了Jar包一鍵重啟的Shell腳本及新服務(wù)器部署的一些經(jīng)驗,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • 詳解RIFF和WAVE音頻文件格式

    詳解RIFF和WAVE音頻文件格式

    本文主要介紹了RIFF文件的格式和WAV音頻文件格式,為后面實現(xiàn)對WAVE文件的讀寫打一個理論基礎(chǔ)。后面打算使用C++標準庫,實現(xiàn)對WAV文件的讀寫
    2022-01-01
  • Visual Studio和Visual Studio Code之間有什么區(qū)別

    Visual Studio和Visual Studio Code之間有什么區(qū)別

    本文給大家介紹的是Visual Studio和Visual Studio Code之間有什么區(qū)別,希望對大家的學習能夠有所幫助
    2020-02-02
  • git 配置多個SSH-Key實現(xiàn)示例

    git 配置多個SSH-Key實現(xiàn)示例

    這篇文章主要為大家介紹了git 配置多個SSH-Key實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Scratch3.0二次開發(fā)之windows環(huán)境下打包成exe的流程

    Scratch3.0二次開發(fā)之windows環(huán)境下打包成exe的流程

    今天通過本文給大家分享Scratch3.0二次開發(fā)之windows環(huán)境下打包成exe的詳細流程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-08-08
  • linux系統(tǒng)使用vscode進行qt開發(fā)的過程分享

    linux系統(tǒng)使用vscode進行qt開發(fā)的過程分享

    最近在Linux上搞Qt,搞的一頭霧水,小編把整個過程記錄下,分享需要的朋友,如果大家對linux系統(tǒng)使用vscode進行qt開發(fā)相關(guān)知識感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • 分享15個美化代碼的代碼語法高亮工具

    分享15個美化代碼的代碼語法高亮工具

    由于技術(shù)類網(wǎng)站經(jīng)常提供一些代碼,分享給大家,但普通的代碼看起來不那么舒服,所以很多人開發(fā)了代碼高亮插件,讓代碼顯示的更漂亮
    2013-09-09

最新評論