Serverless 介紹

很多人看字面會認為serverless是不需要伺服器,其實解釋為:不用擔心維護伺服器這件事會來得恰當。不用擔心伺服器這件事對程式開發者來說是一件非常開心的事,能夠真正把心思放在程式開發,而不是擔心伺服器掛了沒或需要花大把時間做環境建置及撰寫部署手冊(果然是懶人一族)。

舉例來說,有些程式使用Laravel撰寫(運行在LAMP環境),有些用Python環境撰寫,有些則使用node.js或傳統C++撰寫,各種語言需要的運行環境及安裝的套件都不同,傳統我們會需要四台機器(或VM),各自有各自的運行環境需要安裝,但透過Docker化,我們就可以將四種環境各自容器化以便提供服務,對系統管理者來說就不需要安裝、照顧一堆環境(久了要照顧的環境就越來越複雜)。

對程式開發人員來說,程式開發完成後,把需要的環境Container化,只需要一個Service Broker就可以將各種服務組合出來,形成一個完整的服務提供給使用者,加上Container的獨立性與系統不可變動,從資安角度考量安全性遠比傳統伺服器安全許多。其示意圖如下所示:

Serviceless 服務

Serverless 作法

通常可分為:Functions 與 Microservices 兩種,分別可以由這張圖看出來。若是需要長久存在的服務,可以考慮使用Microservices;短期使用的可以採用Functions做法。

使用後即消失的容器

由於Container可以快速建立的特性,社群上已經有相關open source套件讓程式開發者透過命令列執行的方式,讓程式運行完後就停止Container,節省空間或是提供多個Container同步運算,方便讓不同程式語言能夠混用。

範例:讀取輸出的資料

package main

import (
   "github.com/ahmetalpbalkan/go-dexec"
   "github.com/fsouza/go-dockerclient"
   "os"
   "strings"
)

func main() {
   input := `你好  Hello world
from
container
`

   cl, _ := docker.NewClientFromEnv()
   d := dexec.Docker{cl}

   m, _ := dexec.ByCreatingContainer(docker.CreateContainerOptions{ Config: &docker.Config{Image: "busybox"}})

   cmd := d.Command(m, "tr", "[:lower:]", "[:upper:]")  // tr: 字串處理程式(小寫變大寫)
   cmd.Stdin = strings.NewReader(input) // <--
   cmd.Stdout = os.Stdout               // <--

   if err := cmd.Run(); err != nil {
      panic(err)
   }
}

// Output:
	//   HELLO WORLD
	//   FROM
	//   CONTAINER

執行命令列命令

package main

import (
	"fmt"
	"github.com/ahmetalpbalkan/go-dexec"
	"github.com/fsouza/go-dockerclient"
)

func main() {
	cl, _ := docker.NewClientFromEnv()
	d := dexec.Docker{cl}
	m, _ := dexec.ByCreatingContainer(docker.CreateContainerOptions{
		Config: &docker.Config{Image: "busybox"}})

	cmd := d.Command(m, "sh", "-c", "exit 255;")
	err := cmd.Run()
	if err == nil {
		panic("not expecting successful exit")
	}

	if ee, ok := err.(*dexec.ExitError); ok {
		fmt.Printf("exit code=%d\n", ee.ExitCode) // <--
	} else {
		panic(err)
	}
}

下載youtube歌曲

使用別人寫好下載Youtube的container來提供服務。

package main

import (
	"fmt"
	"github.com/ahmetalpbalkan/go-dexec"
	"github.com/fsouza/go-dockerclient"
	"io/ioutil"
)

const (
	url = `https://www.youtube.com/watch?v=2_79sx6V3tU` // don’t judge.
	out = "music.mp3"
)

func main() {
	cl, _ := docker.NewClientFromEnv()
	d := dexec.Docker{cl}

	m, _ := dexec.ByCreatingContainer(docker.CreateContainerOptions{
		Config: &docker.Config{Image: "vimagick/youtube-dl"}})
	cmd := d.Command(m, "sh", "-c", fmt.Sprintf("youtube-dl %s -o - | ffmpeg -i pipe:0 -f mp3 pipe:1", url))
	b, err := cmd.Output()
	if err != nil {
		panic(err)
	}
	if err := ioutil.WriteFile(out, b, 0644); err != nil {
		panic(err)
	}
	fmt.Printf("Saved %d bytes to %s\n", len(b), out)
}

結論

Serverless的好處是可以將程式需要的環境封裝在Docker Container中,大量降低程式設計師對主機的依賴,也降低系統管理人員要一台一台建立運行機器(或VM)的負擔,透過別人寫好的微服務加以組合,就可以形成一個更完整的服務,一方面降低程式重複開發可能;同時又不需要等系統人員將系統建置起來後,再進行程式部署的時間,好處很多,無怪乎是Container的下一階段。

參考資料