Tự làm tool deployer giống ansible playbook

September 20, 2019
deployer Golang ssh excute

Nếu các bạn đã từng sử dụng các tool như Rocketeer, jenkins, ansible,… để deploy thì hẳn đã biết nó dễ dàng cho việc deploy như thế nào. Hôm nay mình sẽ hướng dẫn các bạn tự mình viết scrips đơn giản phục vụ cho việc deployer giống như các tool ở trên bằng Go. Go có goroutine có thể sự dụng cho các bạn muốn deploy multiple server. Hơn nữa còn tiện lợi hơn go sẽ build ra file execute có thể thực thi ngay lập tức mà ko cần phải cài cắm gì.

Cấu trúc folder

.
├── Gopkg.lock
├── Gopkg.toml
├── README.md
├── config.yml
├── main.go
├── templates
└── vendor

Cấu trúc trong Tool của mình như sau.

  • vendor sử dụng để chứa các package add thêm khi development
  • templates sử dụng để chưá các file template có mẫu sẵn có thể copy từ template vào
  • main.go đây là hàm main chính khi bắt đầu khởi chạy
  • config.yml file này chính là file config các thông tin về server Tool sẽ đọc từ file này và thao tác trên server
  • Gopkg.lock, Gopkg.toml là file log và define các package được cài thêm.

Cấu hình file config.

Đầu tiên cần phải khai báo các thông tin server vào file config, như vậy tool mới có thể đọc từ đó và thao tác tới server được. Có thể config như sau

webservers:
  hosts:
    server1:
      address: "127.0.0.1"
      user: "local"
      dir: "/var/www/project"
    server2:
      address: "127.0.0.2"
      user: "local"
      dir: "/var/www/project"

Ở đây đơn giản là mình sẽ sử dụng deploy 2 server cùng lúc. Các bạn muốn deploy cho bao nhiêu server thì có thể khai báo thêm.

Tiếp theo khi đã thao tác vào server công việc chính sẽ là thao tác trên server đó các dòng lệnh để thực hiện build project hoặc install các package liên quan

tasks:
    - name: "install project"
    cmd: "git pull origin"
    args:
        - "master"
    - name: "Install dependencies"
      cmd: "yarn install"
    - name: "Build project"
      cmd: "yarn run product"

Đây là các command để thực hiện deployer cho 1 project nodejs đơn giản. Nếu project của các bạn cần nhiều câu lệnh hơn thì có thể update thêm vào đây.

Vậy là có thể tạm coi xong 1 phần cấu hình config file tiếp theo chúng ta sẽ tới gian đoạn thực thi các config file đó

Main file

Đầu tiên các bạn sẽ phải define struc tương đương với yml file. Cấu trúc như sau

type Configuration struct {
    WebServers
}

type WebServers struct {
    Hosts map[string]Server `yaml:"hosts"`
    Tasks []Task
}

type Server struct {
    Address string `yaml:"address"`
    User    string `yaml:"user"`
    Dir     string `yaml:"dir"`
}

type Task struct {
    Name string   `yaml:"name"`
    Cmd  string   `yaml:"cmd"`
    Args []string `yaml:"args"`
}

Ok như vậy là đã có 1 struct Configuration có thể get toàn bộ thông tin từ yml file rồi. Tiếp đến có thể sử dụng thêm thư viện https://github.com/go-yaml/yaml để Unmarshal từ file yml đó

go get gopkg.in/yaml.v2

Ok rồi vậy làm thế nào để lấy file config ra sử dụng. Các bạn cần viết thêm 1 method getConf như sau

func (c *Configuration) getConf() *Configuration {

    yamlFile, err1 := ioutil.ReadFile("config.yml")
    if err1 != nil {
        log.Printf("yamlFile.Get err   #%v ", err1)
    }

    err2 := yaml.Unmarshal(yamlFile, &c)
    if err2 != nil {
        log.Fatalf("error: %v", err2)
    }

    return c
}

Method này có output là gía trị của config trong yml vậy là các bạn hoàn toàn có thể lấy toàn bộ thông tin trong config. trong file main.go như sau


func main() {
    c := Configuration{}
    c.getConf()
}

OK Như vậy là đã hoàn tất công đoạn config file. Tiếp đến là excute multiple server các bạn cần tạo ra 1 function exec như sau.

func Connection(s Server) {
    cmd := exec.Command(
        "ssh",
        "-t",
        fmt.Sprintf("%s@%s", s.User, s.Address),
        fmt.Sprintf("'cd %s ; ls -al'", s.Dir),
    )
    stdout, err := cmd.Output()
    if err != nil {
        println(err.Error())
        return
    }

    print(string(stdout))
}

Và main function như sau

func main() {
    c := Configuration{}
    c.getConf()
    var wg sync.WaitGroup
    for _, server := range c.WebServers.Hosts {
        wg.Add(1)
        go Connection(server)
    }
    wg.Wait()
}

Tới đây bạn đã có thể connection được vào 1 trong những target server của bạn tuy nhiên để show output khi exec command deploy tuần tự theo từng server và bôi màu cho output với success, error hay warning thì bài sau mình sẽ hướng dẫn chi tiết tiếp.

Các bạn có thể tham khảo các tài liệu liên quan tại đây. Rất cảm ơn các bạn đã tham khảo bài viết của mình.