十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
一般命令
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名注册、网络空间、营销软件、网站建设、龙州网站维护、网站推广。
所谓一般命令,就是在一定时间内会执行完的命令。比如 grep, cat 等等。 执行命令的步骤是:连接,执行,获取结果
连接
连接包含了认证,可以使用 password 或者 sshkey 2种方式来认证。下面的示例为了简单,使用了密码认证的方式来完成连接。
import (
"fmt"
"time"
"golang.org/x/crypto/ssh"
)
func connect(user, password, host string, port int) (*ssh.Session, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
client *ssh.Client
session *ssh.Session
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create session
if session, err = client.NewSession(); err != nil {
return nil, err
}
return session, nil
}
连接的方法很简单,只要提供登录主机的 用户*, *密码*, *主机名或者IP*, *SSH端口
执行,命令获取结果
连接成功后,执行命令很简单
import (
"fmt"
"log"
"os"
"time"
"golang.org/x/crypto/ssh"
)
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Run("ls /; ls /abc")
}
上面代码运行之后,虽然命令正常执行了,但是没有正常输出的结果,也没有异常输出的结果。 要想显示结果,需要将 session 的 Stdout 和 Stderr 重定向 修改 func main 为如下:
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Run("ls /; ls /abc")
}
这样就能在屏幕上显示正常,异常的信息了。
交互式命令
上面的方式无法远程执行交互式命令,比如 top , 远程编辑一个文件,比如 vi /etc/nginx/nginx.conf 如果要支持交互式的命令,需要当前的terminal来接管远程的 PTY。
func main() {
session, err := connect("root", "olordjesus", "dockers.iotalabs.io", 2210)
if err != nil {
log.Fatal(err)
}
defer session.Close()
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
panic(err)
}
defer terminal.Restore(fd, oldState)
// excute command
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
panic(err)
}
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
log.Fatal(err)
}
session.Run("top")
}
hostname是主机名,用于在系统上标识一台机器;
IP地址是在tcp/ip网络中唯一标志一台机器。
联系到实际生活,主机名相当于你家的主人名,如张三家;而IP地址相当于小区内你家的门牌号,如30号楼2单元302
Sealos 是一个 Go 语言开发的简单干净且轻量的 Kubernetes 集群部署工具, Sealos 能很好的支持在生产环境中部署高可用的 Kubernetes 集群。
无论是通过 KeepAlived 还是 HAProxy 进行高可用集群调度都会存在以下一些劣势。
Sealos 高可用实现是通过本地负载方式完成的。本地负载实现方式有多种,比如: IPVS 、 Envoy 、 Nginx 等,而 Sealos 采用的是通过内核 IPVS 来实现的。
本地负载:在每个 Node 节点上都启动一个负载均衡,同时监听集群中的多个 Master 节点。
Sealos 选择通过内核 IPVS 来实现主要有以下几个原因:
1)如果使用 Envoy 等需要在每个节点上都跑一个进程,消耗更多资源。虽然 IPVS 实际上也会多跑一个 lvscare 进程 ,但是 lvscare 只是负责管理 IPVS 规则,原理和 Kube-Proxy 类似。真正的流量直接从内核层面走,不需要把数据包先走到用户态中去处理。
2)使用 Envoy 存在启动优先级的问题,比如:Join 集群时,如果负载均衡没有建立,Kubelet 就会启动失败。使用 IPVS 则不会存在这样的问题,因为我们可以在 Join 集群前先建立好转发规则。
1)解决默认证书有效期只有一年的问题。
2)更方便的实现本地负载。
3)核心的功能均集成到 Kubeadm 中了,Sealos 只管分发和执行上层命令,相对就更轻量了。
离线包包含所有二进制文件配置文件和镜像
服务器用户名:root,服务器密码:123456
升级系统内核
修改Cgroup Driver
设置hostname
多master
kubectl命令自动补全
sealos默认已经帮我们安装命令补全功能。
配置环境
在OSX系统上很容易安装GO的可执行文件:
brew install go
虽然Java或Ruby (或者任何我知道的语言) 可以在本地文件系统的任何地方使用命令,,但是Go项目必须使用单一专用的地址,,并且在$GOPATH环境变量下可用。
第 1 段(可获 1.54 积分)
R e; 7个月前
创建项目对于Logstash插件,Beats项目可以从模板创建。官方文档的说明十分简单。鉴于Go对文件系统上的位置的严格要求,只需按照以下说明生成一个新的即可使用的Go项目。默认模板代码将在控制台中重复发送带增量计数器的事件:./redditbeat -e -d "*"
2016/12/13 22:55:56.013362 beat.go:267: INFO
Home path: [/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat]
Config path: [/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat]
Data path: [/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat/data]
Logs path: [/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat/logs]
2016/12/13 22:55:56.013390 beat.go:177: INFO Setup Beat: redditbeat; Version: 6.0.0-alpha1
2016/12/13 22:55:56.013402 processor.go:43: DBG Processors:
2016/12/13 22:55:56.013413 beat.go:183: DBG Initializing output plugins
2016/12/13 22:55:56.013417 logp.go:219: INFO Metrics logging every 30s
2016/12/13 22:55:56.013518 output.go:167: INFO Loading template enabled. Reading template file:
/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat/redditbeat.template.json
2016/12/13 22:55:56.013888 output.go:178: INFO Loading template enabled for Elasticsearch 2.x. Reading template file:
/Users/i303869/projects/private/go/src/github.com/nfrankel/redditbeat/redditbeat.template-es2x.json
2016/12/13 22:55:56.014229 client.go:120: INFO Elasticsearch url:
2016/12/13 22:55:56.014272 outputs.go:106: INFO Activated elasticsearch as output plugin.
2016/12/13 22:55:56.014279 publish.go:234: DBG Create output worker
2016/12/13 22:55:56.014312 publish.go:276: DBG No output is defined to store the topology.
The server fields might not be filled.
2016/12/13 22:55:56.014326 publish.go:291: INFO Publisher name: LSNM33795267A
2016/12/13 22:55:56.014386 async.go:63: INFO Flush Interval set to: 1s
2016/12/13 22:55:56.014391 async.go:64: INFO Max Bulk Size set to: 50
2016/12/13 22:55:56.014395 async.go:72: DBG create bulk processing worker (interval=1s, bulk size=50)
2016/12/13 22:55:56.014449 beat.go:207: INFO redditbeat start running.
2016/12/13 22:55:56.014459 redditbeat.go:38: INFO redditbeat is running! Hit CTRL-C to stop it.
2016/12/13 22:55:57.370781 client.go:184: DBG Publish: {
"@timestamp": "2016-12-13T22:54:47.252Z",
"beat": {
"hostname": "LSNM33795267A",
"name": "LSNM33795267A",
"version": "6.0.0-alpha1"
},
"counter": 1,
"type": "redditbeat"
}
第 2 段(可获 0.73 积分)
R e; 7个月前
关于命令行参数:-e记录到标准err,而-d“*”启用所有调试选择器。有关参数的完整列表,请键入./redditbeat --help。编码Go代码位于.go文件中(令人惊讶...)在$ GOPATH / src文件夹的项目子文件夹中。配置类型第一个有趣的文件是config / config.go,它定义了一个结构来声明Beat的可能参数。至于前面的Logstash插件,让我们添加一个subreddit参数,并设置它的默认值:type Config struct {
Period time.Duration `config:"period"`
Subreddit string `config:"subreddit"`
}
var DefaultConfig = Config {
Period: 15 * time.Second,
Subreddit: "elastic",
}
第 3 段(可获 0.89 积分)
R e; 7个月前
Beater TypeBeat本身的代码在beater / redditbean.go中找到。默认模板为Beat和三个函数创建一个struct:Beat构造函数—用来读取配置: func New(b *beat.Beat, cfg *common.Config) (beat.Beater, error) { ... }
Run 函数- 需要覆盖Beat的主要功能: func (bt *Redditbeat) Run(b *beat.Beat) error { ... }
Stop 函数管理优雅关闭: func (bt *Redditbeat) Stop() { ... }
Note 1:在Go中没有明确的接口实现。实现了 interface 中的所有方法,即创建一个隐式继承关系. 出于写文档的目的,这是 Beater 接口:type Beater interface {
Run(b *Beat) error
Stop()
}
第 4 段(可获 0.93 积分)
R e; 7个月前
因此,由于Beat结构实现了Run和Stop,它是一个Beater。Note 2: 在Go中没有类的概念,所以方法不能在一个具体类型上声明。但是,它存在扩展函数的概念:可以添加行为到一个类型(在单个包中)的函数。它需要声明receiver 类型:这是在fun关键字和函数名之间完成的 - 这里是指Redditbeat类型(或者更准确地说,是一个指向Redditbeat类型的指针,但是这里有一个隐式转换)。构造函数和Stop函数可以保持不变,无论什么特性都应该在Run函数中。在这种情况下,功能是调用Reddit REST API并为每个Reddit帖子发送一条消息。
第 5 段(可获 1.59 积分)
R e; 7个月前
最终代码如下所示:func (bt *Redditbeat) Run(b *beat.Beat) error {
bt.client = b.Publisher.Connect()
ticker := time.NewTicker(bt.config.Period)
reddit := "" + bt.config.Subreddit + "/.json"
client := http.Client {}
for {
select {
case -bt.done:
return nil
case -ticker.C:
}
req, reqErr := http.NewRequest("GET", reddit, nil)
req.Header.Add("User-Agent", "Some existing header to bypass 429 HTTP")
if (reqErr != nil) {
panic(reqErr)
}
resp, getErr := client.Do(req)
if (getErr != nil) {
panic(getErr)
}
body, readErr := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if (readErr != nil) {
panic(readErr)
}
trimmedBody := body[len(prefix):len(body) - len(suffix)]
messages := strings.Split(string(trimmedBody), separator)
for i := 0; i len(messages); i ++ {
event := common.MapStr{
"@timestamp": common.Time(time.Now()),
"type": b.Name,
"message": "{" + messages[i] + "}",
}
bt.client.PublishEvent(event)
}
}
}
第 6 段(可获 0.09 积分)
R e; 7个月前
这里是对最重要的几部分的解释:line 4: 通过连接字符串创建Reddit REST URL,包括配置Subreddit参数。记住,它的默认值已在config.go文件中定义。line 5: 引用httpClient类型line 12: 创建新的HTTP请求。注意Go允许多个返回值。line 13: 如果没有设置标准请求头,Reddit的API将返回429状态码。line 14: Go标准错误不通过异常处理,而是随着常规返回值返回。根据Golang wiki:指示调用者的错误条件,应通过返回错误值来完成line 15: panic() 函数类似于在Java中抛出异常, 被处理时推到栈顶。 有关详细信息,请查看相关文档。line 17: 执行HTTP请求。line 21: 将响应主体读入字节数组。line 22: 关闭主体流。注意defer关键字:defer语句延迟函数的执行,直到环绕的函数返回。line 26: 创建整个响应主体字节数组的切片 - 对数组的一部分的引用。实质上,它删除了前缀和后缀以保持相关的JSON值。之后将字节数组解析成JSON。line 27: 分割切片以单独获取每个JSON片段。line 29: 将消息创建为简单的字典结构。line 34: 发送。
第 7 段(可获 3.11 积分)
R e; 7个月前
配置, 构建, 运行默认配置参数可以在项目根目录下的redditbeat.yml文件中找到。请注意,redditbeat.full.yml中列出了其他常见的Beat参数,以及相关注释。关于Beats的一个有趣的事情是,他们的消息可以直接发送到Elasticsearch或Logstash进行进一步处理。这在上述配置文件中配置。redditbeat:
period: 10s
output.elasticsearch:
hosts: ["localhost:9200"]
output.logstash:
hosts: ["localhost:5044"]
enabled: true
第 8 段(可获 0.78 积分)
R e; 7个月前
此配置片段将每10秒循环运行Run方法,并将消息发送到在localhost上运行的Logstash实例在端口5044上。这可以在运行Beat时被覆盖(见下文)。注意:为了使Logstash接受来自Beats的消息,必须安装Logstash Beat插件,并且必须为Beats配置Logstash的input:input {
beats {
port = 5044
}
}
要构建项目,请在项目的根目录中键入make。它将创建一个可以运行的可执行文件。./redditbeat -e -E redditbeat.subreddit=java
-E参数可以覆盖在的redditbeat.yml配置文件中找到的参数(见上文)。在这里,它设置subreddit读为“java”,而不是默认的“elastic”。
第 9 段(可获 1.3 积分)
R e; 7个月前
输出如下所示:2016/12/17 14:51:19.748329 client.go:184: DBG Publish: {
"@timestamp": "2016-12-17T14:51:19.748Z",
"beat": {
"hostname": "LSNM33795267A",
"name": "LSNM33795267A",
"version": "6.0.0-alpha1"
},
"message": "{
\"kind\": \"t3\", \"data\": {
\"contest_mode\": false, \"banned_by\": null,
\"domain\": \"blogs.oracle.com\", \"subreddit\": \"java\", \"selftext_html\": null,
\"selftext\": \"\", \"likes\": null, \"suggested_sort\": null, \"user_reports\": [],
\"secure_media\": null, \"saved\": false, \"id\": \"5ipzgq\", \"gilded\": 0,
\"secure_media_embed\": {}, \"clicked\": false, \"report_reasons\": null,
\"author\": \"pushthestack\", \"media\": null, \"name\": \"t3_5ipzgq\", \"score\": 11,
\"approved_by\": null, \"over_18\": false, \"removal_reason\": null, \"hidden\": false,
\"thumbnail\": \"\", \"subreddit_id\": \"t5_2qhd7\", \"edited\": false,
\"link_flair_css_class\": null, \"author_flair_css_class\": null, \"downs\": 0,
\"mod_reports\": [], \"archived\": false, \"media_embed\": {}, \"is_self\": false,
\"hide_score\": false, \"spoiler\": false,
\"permalink\": \"/r/java/comments/5ipzgq/jdk_9_will_no_longer_bundle_javadb/\",
\"locked\": false, \"stickied\": false, \"created\": 1481943248.0,
\"url\": \"\",
\"author_flair_text\": null, \"quarantine\": false,
\"title\": \"JDK 9 will no longer bundle JavaDB\", \"created_utc\": 1481914448.0,
\"link_flair_text\": null, \"distinguished\": null, \"num_comments\": 4,
\"visited\": false, \"num_reports\": null, \"ups\": 11
}
}",
"type": "redditbeat"
}
1、gethostbyname()函数属于WinSock API库,而在使用WinSock API之前,必须调用WSA-Startup函数,只有该函数成功返回(表示应用程序与WinSock库成功地建立起连接),应用程序才可以调用其他Windows Sockets DLL中的函数。当程序将要结束时,又必须调用WSACleanup 函数进行清理工作,以便释放其占用的资源。WSACleanup 函数用来结束Windows Sockets DLL的使用。
2、例程:
char hostname[256];
int iRet = 0;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,1),wsaData)) //调用Windows Sockets DLL
{
printf("Winsock无法初始化!\n");
WSACleanup();
return 0;
}
memset(hostname, 0, 256);
iRet = gethostname(hostname, sizeof(hostname));
if(iRet != 0 )
{
printf( "get hostname error:%d\n", iRet);
}
printf("%s\n", hostname);
网关=反向代理+负载均衡+各种策略,技术实现也有多种多样,有基于 nginx 使用 lua 的实现,比如 openresty、kong;也有基于 zuul 的通用网关;还有就是 golang 的网关,比如 tyk。
这篇文章主要是讲如何基于 golang 实现一个简单的网关。
转自: troy.wang/docs/golang/posts/golang-gateway/
整理:go语言钟文文档:
启动两个后端 web 服务(代码)
这里使用命令行工具进行测试
具体代码
直接使用基础库 httputil 提供的NewSingleHostReverseProxy即可,返回的reverseProxy对象实现了serveHttp方法,因此可以直接作为 handler。
具体代码
director中定义回调函数,入参为*http.Request,决定如何构造向后端的请求,比如 host 是否向后传递,是否进行 url 重写,对于 header 的处理,后端 target 的选择等,都可以在这里完成。
director在这里具体做了:
modifyResponse中定义回调函数,入参为*http.Response,用于修改响应的信息,比如响应的 Body,响应的 Header 等信息。
最终依旧是返回一个ReverseProxy,然后将这个对象作为 handler 传入即可。
参考 2.2 中的NewSingleHostReverseProxy,只需要实现一个类似的、支持多 targets 的方法即可,具体实现见后面。
作为一个网关服务,在上面 2.3 的基础上,需要支持必要的负载均衡策略,比如:
随便 random 一个整数作为索引,然后取对应的地址即可,实现比较简单。
具体代码
使用curIndex进行累加计数,一旦超过 rss 数组的长度,则重置。
具体代码
轮询带权重,如果使用计数递减的方式,如果权重是5,1,1那么后端 rs 依次为a,a,a,a,a,b,c,a,a,a,a…,其中 a 后端会瞬间压力过大;参考 nginx 内部的加权轮询,或者应该称之为平滑加权轮询,思路是:
后端真实节点包含三个权重:
操作步骤:
具体代码
一致性 hash 算法,主要是用于分布式 cache 热点/命中问题;这里用于基于某 key 的 hash 值,路由到固定后端,但是只能是基本满足流量绑定,一旦后端目标节点故障,会自动平移到环上最近的那么个节点。
实现:
具体代码
每一种不同的负载均衡算法,只需要实现添加以及获取的接口即可。
然后使用工厂方法,根据传入的参数,决定使用哪种负载均衡策略。
具体代码
作为网关,中间件必不可少,这类包括请求响应的模式,一般称作洋葱模式,每一层都是中间件,一层层进去,然后一层层出来。
中间件的实现一般有两种,一种是使用数组,然后配合 index 计数;一种是链式调用。
具体代码