最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

1、Code-Server下載部署

1.1 Code-Server下載

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

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

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

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.進(jìn)入code-server目錄:

cd code-server-4.6.1-linux-amd64

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

export PASSWORD="xxxx"

4.啟動(dòng)code-server

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

在瀏覽器中輸入ip:8888來(lái)訪問(wèn)如下:

后臺(tái)運(yùn)行的方式:

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

1.3 Docker部署Code-Server

接下來(lái)將介紹使用Docker的方式來(lái)部署Code-Server:

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

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

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.運(yùn)行容器

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

2. 一個(gè)小問(wèn)題

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

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

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

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

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

2.1 端口監(jiān)聽

這個(gè)程序會(huì)每隔一秒獲取一下有哪些端口處于LISTEN狀態(tài),然后對(duì)比上一次的狀態(tài),看是否有新的端口被監(jiān)聽。當(dāng)我們監(jiān)聽了新的80端口后,就會(huì)輸出: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()          // 程序啟動(dòng)后先獲取一次處于Listen狀態(tài)的端口
	set := map[uint16]struct{}{}
	for _, port := range ports {
		set[port] = struct{}{}
	}

	for {                                   // 然后每隔一秒獲取一次,并與前一次的信息進(jìn)行對(duì)比,查找是否啟動(dòng)了新的端口
		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")          // 運(yùn)行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)                         // 對(duì)結(jié)果進(jìn)行解析
}

func (p *PortListener) parsePort(msg []byte) []uint16 {       // 解析出處于LISTEN狀態(tài)的端口,只要端口號(hào)
	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插件

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

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

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

npm install -g yo generator-code

2.創(chuàng)建項(xiàng)目,選擇要?jiǎng)?chuàng)建的項(xià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è)置定時(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 + ",是否在瀏覽器中訪問(wèn)?", "是", "否", "不再提示")
                .then(result=> {
                    if (result === "是") {
                        // 在瀏覽器中打開來(lái)訪問(wèn)代理服務(wù)器,后面帶上端口信息,以便代理服務(wù)器知道訪問(wèn)容器的哪個(gè)端口
                        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)建項(xiàng)目,首先安裝vsce庫(kù),再打包

npm i -g vsce
vsce package

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

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

然后在瀏覽器中的vscode中選擇vsix文件來(lái)安裝插件

安裝完之后,我們的插件在vscode打開后就會(huì)啟動(dòng),然后每隔一秒查詢一個(gè)端口情況。

測(cè)試

接下來(lái),測(cè)試一下插件:

在vscode中寫了一個(gè)http服務(wù)器,然后啟動(dòng)這個(gè)服務(wù)器,看插件是否能發(fā)現(xiàn)這個(gè)端口被監(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")
}

運(yùn)行http服務(wù)器:

go run main.go

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

但是現(xiàn)在在瀏覽器中打開是訪問(wèn)不了容器中的http服務(wù)器的,因?yàn)槎丝跊](méi)有被映射到主機(jī)端口上。

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

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

代碼如下:

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:]                             // 丟棄第一個(gè)'/'
		idx := strings.Index(all, "/")
		var url string
		if idx < 0 {                              // 只有端口
			url = fmt.Sprintf("http://172.17.0.3:%s", all)
		} else {                                 // 有端口和其它訪問(wèn)路徑
			port := all[:idx]
			url = fmt.Sprintf("http://172.17.0.3:%s%s", port, all[idx:])
		}
		resp, err := http.Get(url)               // 訪問(wèn)容器中的服務(wù)器
		if err != nil {
			ctx.Status(http.StatusBadRequest)
			return
		}
		io.Copy(ctx.Writer, resp.Body)            // 轉(zhuǎn)發(fā)響應(yīng)
	})

	engine.Run(":80")
}

在主機(jī)服務(wù)器上運(yùn)行代理服務(wù)器,不要使用容器來(lái)啟動(dòng):

go build 
nohup ./porxy_server &           # 后臺(tái)運(yùn)行

然后我們?cè)賳?dòng)瀏覽器vscode中的服務(wù)器看是否可以訪問(wèn)到:

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

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

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

相關(guān)文章

  • yum的基本用法和實(shí)例(推薦)

    yum的基本用法和實(shí)例(推薦)

    這篇文章主要介紹了Linux(centos8)下的yum的基本用法和實(shí)例,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • VSCode打開Json文件格式化的簡(jiǎn)單步驟

    VSCode打開Json文件格式化的簡(jiǎn)單步驟

    JSON是現(xiàn)代Web應(yīng)用程序中不可或缺的文件格式之一,在VSCode中我們可以調(diào)整我們JSON文件的格式以便更好地閱讀,下面這篇文章主要給大家介紹了關(guān)于VSCode打開Json文件格式化的簡(jiǎn)單步驟,需要的朋友可以參考下
    2024-01-01
  • Web開發(fā)人員常用速查手冊(cè) 英文集合推薦

    Web開發(fā)人員常用速查手冊(cè) 英文集合推薦

    不管你是多么優(yōu)秀的程序員,你都不可能記住一切。在你編寫程序的過(guò)程中碰到問(wèn)題需要查閱手冊(cè)的時(shí)候,若有現(xiàn)成的手冊(cè)可參考則可以為你節(jié)省很多時(shí)間。
    2011-04-04
  • 微信小程序設(shè)置http請(qǐng)求的步驟詳解

    微信小程序設(shè)置http請(qǐng)求的步驟詳解

    這篇文章給大家介紹了微信小程序如何進(jìn)行http請(qǐng)求的詳細(xì)步驟,相信對(duì)大家學(xué)習(xí)微信小程序網(wǎng)絡(luò)請(qǐng)求會(huì)有所幫助,有需要的朋友們下面來(lái)一起看看吧。
    2016-09-09
  • SpringSecurity框架簡(jiǎn)介及與shiro特點(diǎn)對(duì)比

    SpringSecurity框架簡(jiǎn)介及與shiro特點(diǎn)對(duì)比

    這篇文章是SpringSecurity框架的入門篇,主要為大家介紹了SpringSecurity框架簡(jiǎn)介及與shiro優(yōu)缺點(diǎn)對(duì)比有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03
  • VSCode方便實(shí)用必備的使用技巧大全

    VSCode方便實(shí)用必備的使用技巧大全

    Visual?Studio?Code?(VSCode)是一款功能強(qiáng)大的開源代碼編輯器,免費(fèi)開源,本文將分享一些常用的VSCode小技巧,幫助你提升開發(fā)效率和編程體驗(yàn),專注于業(yè)務(wù)邏輯的開發(fā),無(wú)論是文件導(dǎo)航、代碼編輯、調(diào)試還是終端操作,VSCode?都能提供非常豐富的功能,幫助你快速構(gòu)建高質(zhì)量的應(yīng)用
    2025-02-02
  • 在命令行用 sort 進(jìn)行排序的方法

    在命令行用 sort 進(jìn)行排序的方法

    這篇文章主要介紹了在命令行用 sort 進(jìn)行排序的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • CentOS下安裝Jenkins的完整步驟

    CentOS下安裝Jenkins的完整步驟

    Jenkins是一款由Java編寫的開源的持續(xù)集成工具,下面這篇文章主要介紹了CentOS下安裝Jenkins的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • yum安裝telnet的步驟

    yum安裝telnet的步驟

    Telnet協(xié)議是TCP/IP協(xié)議族中的一員,是Internet遠(yuǎn)程登錄服務(wù)的標(biāo)準(zhǔn)協(xié)議和主要方式,Telnet是常用的遠(yuǎn)程控制Web服務(wù)器的方法,本文給大家分享yum安裝telnet的步驟,感興趣的朋友一起看看吧
    2020-05-05
  • IE 瀏覽器安全級(jí)別詳情及區(qū)別小結(jié)

    IE 瀏覽器安全級(jí)別詳情及區(qū)別小結(jié)

    排查問(wèn)題時(shí),定位到可能和當(dāng)前瀏覽器的安全級(jí)別設(shè)置有關(guān),順便整理了下Windows 7下IE9安全級(jí)別的詳情內(nèi)容,及各安全級(jí)別下的默認(rèn)設(shè)置差異
    2016-01-01

最新評(píng)論

娄底市| 华容县| 济宁市| 耒阳市| 通河县| 南投市| 贵南县| 朝阳市| 芦山县| 图木舒克市| 班戈县| 鲁甸县| 阳山县| 天津市| 金山区| 封丘县| 威远县| 吉首市| 凤阳县| 微山县| 深州市| 江阴市| 汪清县| 牙克石市| 浦县| 凌云县| 九台市| 衡水市| 洞口县| 循化| 台安县| 呼和浩特市| 浦城县| 吉水县| 潜江市| 张家港市| 会宁县| 潍坊市| 巩义市| 府谷县| 涪陵区|