本文目錄一覽:
- 1、用docker搭建一個高可用可擴展的服務支撐系統怎麼做
- 2、如何使用Go語言實現遠程執行命令
- 3、程序需要在有auth認證的mongodb下運行eval函數或命令時提示無權限
- 4、Golang 綁定mac和ip地址,限制服務器
用docker搭建一個高可用可擴展的服務支撐系統怎麼做
一種方案為Haproxy+etcd+confd,採用鬆散式的組織結構,但各個組件之間的通訊是非常嚴密的,且擴展性更強,定製也更加靈活。
一、架構優勢
約定由Haproxy+etcd+confd+Docker構建的基礎服務平台簡稱「HECD」 架構,整合了多種開源組件,看似鬆散的結構,事實上已經是一個有機的整體,它們互相聯繫、互相作用,是Docker生態圈中最理想的組合之一,具有以下優勢:
自動、實時發現及無感知服務刷新;
支持任意多台Docker主宿機;
支持多種APP接入且打散至不分主宿機;
採用Etcd存儲信息,集群支持可靠性高;
採用Confd配置引擎,支持各類接入層,如Nginx;
支持負載均衡、故障遷移;
具備資源彈性,伸縮自如(通過生成、銷毀容器實現);
二、架構說明
在HECD架構中,首先管理員操作Docker Client,除了提交容器(Container)啟動與停止指令外,還通過REST-API方式向Etcd(K/V)存儲組件註冊容器信息,包括容器名稱、主宿機IP、映射端口等。Confd配置組件會定時查詢Etcd組件獲取最新的容器信息,根據定義好的配置模板生成Haproxy配置文件Haproxy.cfg,並且自動reload haproxy服務。用戶在訪問業務服務時,完全沒有感知後端APP的上線、下線、切換及遷移,達到了自動發現、高可用的目的。詳細架構圖見圖1-1。
圖1-1 平台架構圖
為了方便大家理解各組件間的關係,通過圖1-2進行架構流程梳理,首先管理員通過Shell或API操作容器,下一步將容器信息註冊到Etcd組件,Confd組件會定時查詢Etcd,獲取已經註冊到Etcd中容器信息,最後通過Confd的模板引擎生成Haproxy配置,整個流程結束。
圖1-2架構流程圖
了解架構流程後,我們逐一對流程中各組件進行詳細介紹。
1、Etcd介紹
Etcd是一個高可用的 Key/Value 存儲系統,主要用於分享配置和服務發現。
簡單:支持 curl 方式的用戶 API (HTTP+JSON)
安全:可選 SSL 客戶端證書認證
快速:單實例可達每秒 1000 次寫操作
可靠:使用 Raft 實現分佈式
2、Confd介紹
Confd是一個輕量級的配置管理工具。通過查詢Etcd,結合配置模板引擎,保持本地配置最新,同時具備定期探測機制,配置變更自動reload。
3、Haproxy介紹
HAProxy是提供高可用性、負載均衡以及基於TCP和HTTP應用的代理,支持虛擬主機,它是免費、快速並且可靠的一種解決方案。(來源百科)
三、架構部署
平台環境基於Centos6.5+Docker1.2構建,其中Etcd的版本為etcd version 0.5.0-alpha,Confd版本為confd 0.6.2,Haproxy版本為HA-Proxy version 1.4.24。下面對平台的運行環境、安裝部署、組件說明等進行詳細說明,環境設備角色表如下:
1、組件安裝
1.1 Docker安裝
SSH終端登錄192.168.1.22服務器,執行以下命令:
# yum -y install docker-io
# service docker start
# chkconfig docker on
1.2 Haproxy、confd安裝
SSH終端登錄192.168.1.20服務器,執行以下命令:
1、haproxy
# yum –y install haproxy
2、confd
# wget
# mv confd /usr/local/bin/confd
# chmod +x /usr/local/bin/confd
# /usr/local/bin/confd -version
confd 0.6.2
1.3 Etcd安裝
SSH終端登錄192.168.1.21服務器,執行以下命令:
# yum -y install golang
# mkdir -p /home/install cd /home/install
# git clone
# cd etcd
# ./build
# cp bin/etcd /bin/etcd
# /bin/etcd -version
etcd version 0.5.0-alpha
2、組件配置
2.1 Etcd配置
由於etcd是一個輕量級的K/V存儲平台,啟動時指定相關參數即可,無需配置。
# /bin/etcd -peer-addr 192.168.1.21:7001 -addr 192.168.1.21:4001 -data-dir /data/etcd -peer-bind-addr 0.0.0.0:7001 -bind-addr 0.0.0.0:4001
由於etcd具備多機支持,參數「-peer-addr」指定與其它節點通訊的地址;參數「-addr」指定服務監聽地址;參數「-data-dir」為指定數據存儲目錄。
由於etcd是通過REST-API方式進行交互,常見操作如下:
1) 設置(set) key操作
# curl -L -d value=”this is awesome”
{“action”:”set”,”node”:{“key”:”/mykey”,”value”:”this is awesome”,”modifiedIndex”:28,”createdIndex”:28}}
2) 獲取(get) key信息
# curl -L
{“action”:”get”,”node”:{“key”:”/mykey”,”value”:”this is awesome”,”modifiedIndex”:28,”createdIndex”:28}}
3) 刪除key信息
# curl -L {“action”:”delete”,”node”:{“key”:”/mykey”,”modifiedIndex”:29,”createdIndex”:28},”prevNode”:{“key”:”/mykey”,”value”:”this is awesome”,”modifiedIndex”:28,”createdIndex”:28}} 更多操作API見。
2.2 Confd+Haproxy配置
由於Haproxy的配置文件是由Confd組件生成,要求Confd務必要與haproxy安裝在同一台主機上,Confd的配置有兩種,一種為Confd資源配置文件,默認路徑為「/etc/confd/conf.d」目錄,另一種為配置模板文件,默認路徑為「/etc/confd/templates」。具體配置如下:
創建配置文件目錄
# mkdir -p /etc/confd/{conf.d,templates}
(1)配置資源文件
詳細見以下配置文件,其中「src」為指定模板文件名稱(默認到路徑/etc/confd/templates中查找);「dest」指定生成的Haproxy配置文件路徑;「keys」指定關聯Etcd中key的URI列表;「reload_cmd」指定服務重載的命令,本例中配置成haproxy的reload命令。
【/etc/confd/conf.d/ haproxy.toml】
[template]
src = “haproxy.cfg.tmpl”
dest = “/etc/haproxy/haproxy.cfg”
keys = [
“/app/servers”,
]
reload_cmd = “/etc/init.d/haproxy reload”
(2)配置模板文件
Confd模板引擎採用了Go語言的文本模板,更多見,具備簡單的邏輯語法,包括循環體、處理函數等,本示例的模板文件如下,通過range循環輸出Key及Value信息。
【/etc/confd/templates/haproxy.cfg.tmpl】
global
log 127.0.0.1 local3
maxconn 5000
uid 99
gid 99
daemon
defaults
log 127.0.0.1 local3
mode http
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
listen frontend 0.0.0.0:80
mode http
balance roundrobin
maxconn 2000
option forwardfor
{{range gets “/app/servers/*”}}
server {{base .Key}} {{.Value}} check inter 5000 fall 1 rise 2
{{end}}
stats enable
stats uri /admin-status
stats auth admin:123456
stats admin if TRUE
(3)模板引擎說明
本小節詳細說明Confd模板引擎基礎語法與示例,下面為示例用到的KEY信息。
# curl -XPUT value=”192.168.1.22:49156″
# curl -XPUT value=”192.168.1.22:49158″
# curl -XPUT value=”192.168.1.22:49160″
# curl -XPUT value=”192.168.1.22:49162″1、base
作為path.Base函數的別名,獲取路徑最後一段。
{{ with get “/app/servers/prickly_blackwell”}}
server {{base .Key}} {{.Value}} check
{{end}}
prickly_blackwell 192.168.1.22:49162
2、get
返回一對匹配的KV,找不到則返回錯誤。
{{with get “/app/servers/prickly_blackwell”}}
key: {{.Key}}
value: {{.Value}}
{{end}}
/app/servers/prickly_blackwell 192.168.1.22:49162
3、gets
{{range gets “/app/servers/*”}}
{{.Key}} {{.Value}}
{{end}}
/app/servers/backstabbing_rosalind 192.168.1.22:49156
/app/servers/cocky_morse 192.168.1.22:49158
/app/servers/goofy_goldstine 192.168.1.22:49160
app/servers/prickly_blackwell 192.168.1.22:49162
4、getv
返回一個匹配key的字符串型Value,找不到則返回錯誤。
{{getv “/app/servers/cocky_morse”}}
192.168.1.22:49158
5、getvs
返回所有匹配key的字符串型Value,找不到則返回錯誤。
{{range getvs “/app/servers/*”}}
value: {{.}}
{{end}}
value: 192.168.1.22:49156
value: 192.168.1.22:49158
value: 192.168.1.22:49160
value: 192.168.1.22:49162
6、split
對輸入的字符串做split處理,即將字符串按指定分隔符拆分成數組。
{{ $url := split (getv “/app/servers/cocky_morse”) “:” }}
host: {{index $url 0}}
port: {{index $url 1}}
host: 192.168.1.22
port: 49158
7、ls
返回所有的字符串型子key,找不到則返回錯誤。
{{range ls “/app/servers/”}}
subkey: {{.}}
{{end}}
subkey: backstabbing_rosalind
subkey: cocky_morse
subkey: goofy_goldstine
subkey: prickly_blackwell
8、lsdir
返回所有的字符串型子目錄,找不到則返回一個空列表。
{{range lsdir “/app/”}}
subdir: {{.}}
{{end}}
subdir: servers
(4)啟動confd及haproxy服務
下面為啟動Confd服務命令行,參數「interval」為指定探測etcd的頻率,單位為秒,參數「-node」為指定etcd監聽服務主地址,以便獲取容器信息。
# /usr/local/bin/confd -verbose -interval 10 -node ‘192.168.1.21:4001’ -confdir /etc/confd /var/log/confd.log
# /etc/init.d/haproxy start nbsp;
如何使用Go語言實現遠程執行命令
一般命令
所謂一般命令,就是在一定時間內會執行完的命令。比如 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”)
}
程序需要在有auth認證的mongodb下運行eval函數或命令時提示無權限
mongodb本來是沒有權限問題的,因為默認設置無用戶無密碼,
為了保障安全,需要手動設置一個賬號和用戶,這裡不細談如何創建有權限認證的mongodb賬號(如mysql的root用戶)
筆者用的是golang10.1+mongodb3.6,之前項目是不認證的程序,加了認證之後提示沒有權限操作
那麼首先在
連接地址處加上用戶和密碼(馬賽克處是密碼)
運行單元測試發現,增查刪改功能正常,但是
eval函數還是說我沒有授權
看了官網文檔說
需要grant一個anyAction on anyResource的user
參考於
解決辦法如下:
登錄mongodb,執行以下命令:
其中yourusername和yourpassword是自己設置的用戶和密碼(這個用戶前提是已經有了root權限)
問題解決。
Golang 綁定mac和ip地址,限制服務器
實際業務:go 二進制文件在私有化部署中,需要對客戶的服務器mac和ip進行綁定,系統只能運行在綁定的服務器上。把mac和ip地址配置到config中。
運行效果:系統可正常編譯,正常訪問,在用戶Auth接口進行核對。
//檢驗Mac和內網IP,測試環境不做校驗
func (c *CommonBase)CheckMacAndIp()error {
ipCfg :=g.Cfg().GetString(“machine.Ipaddr”)
macCfg :=g.Cfg().GetString(“machine.Macip”)
if ipCfg ==”127.0.0.1″ {
return nil
}
macArray,_ :=gipv4.GetMacArray()
if len(macArray) ==0 {
return gerror.New(“mac地址獲取失敗”)
}
if garray.NewStrArrayFrom(macArray).Contains(macCfg) ==false {
return gerror.New(“示授權的應用MAC,請聯繫”)
}
ipArray,_ :=gipv4.GetIpArray()
ipIntranetArray,_ :=gipv4.GetIntranetIpArray()
if len(ipArray) ==0 len(ipIntranetArray) ==0 {
return gerror.New(“ip地址獲取失敗”)
}
if garray.NewStrArrayFrom(ipArray).Merge(ipIntranetArray).Contains(ipCfg) ==false {
return gerror.New(“示授權的應用IP,請聯繫”)
}
return nil
}
項目使用GoFrame框架1.6。考慮到客戶可能會對內存數據做分析破解,可以把mac和ip地址做AES加密。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/161021.html