mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-19 12:36:38 +00:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
3ee52c6ed7 | |||
da16bdeee8 | |||
ad97b6db58 | |||
5bb68e15f5 |
2
Gopkg.lock
generated
2
Gopkg.lock
generated
@ -440,6 +440,7 @@
|
|||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
input-imports = [
|
||||||
|
"github.com/alexellis/go-execute",
|
||||||
"github.com/containerd/containerd",
|
"github.com/containerd/containerd",
|
||||||
"github.com/containerd/containerd/cio",
|
"github.com/containerd/containerd/cio",
|
||||||
"github.com/containerd/containerd/containers",
|
"github.com/containerd/containerd/containers",
|
||||||
@ -451,6 +452,7 @@
|
|||||||
"github.com/spf13/cobra",
|
"github.com/spf13/cobra",
|
||||||
"github.com/vishvananda/netlink",
|
"github.com/vishvananda/netlink",
|
||||||
"github.com/vishvananda/netns",
|
"github.com/vishvananda/netns",
|
||||||
|
"golang.org/x/sys/unix",
|
||||||
]
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
32
Gopkg.toml
32
Gopkg.toml
@ -1,30 +1,3 @@
|
|||||||
# Gopkg.toml example
|
|
||||||
#
|
|
||||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
|
||||||
# for detailed Gopkg.toml documentation.
|
|
||||||
#
|
|
||||||
# required = ["github.com/user/thing/cmd/thing"]
|
|
||||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project"
|
|
||||||
# version = "1.0.0"
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project2"
|
|
||||||
# branch = "dev"
|
|
||||||
# source = "github.com/myfork/project2"
|
|
||||||
#
|
|
||||||
# [[override]]
|
|
||||||
# name = "github.com/x/y"
|
|
||||||
# version = "2.4.0"
|
|
||||||
#
|
|
||||||
# [prune]
|
|
||||||
# non-go = false
|
|
||||||
# go-tests = true
|
|
||||||
# unused-packages = true
|
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/containerd/containerd"
|
name = "github.com/containerd/containerd"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -37,6 +10,11 @@
|
|||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
version = "0.0.5"
|
version = "0.0.5"
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/alexellis/go-execute"
|
||||||
|
version = "0.3.0"
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
75
cmd/install.go
Normal file
75
cmd/install.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
systemd "github.com/alexellis/faasd/pkg/systemd"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var installCmd = &cobra.Command{
|
||||||
|
Use: "install",
|
||||||
|
Short: "Install faasd",
|
||||||
|
RunE: runInstall,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runInstall(_ *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
|
err := binExists("/usr/local/bin/", "faas-containerd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = binExists("/usr/local/bin/", "netns")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.InstallUnit("faas-containerd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.InstallUnit("faasd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.DaemonReload()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.Enable("faas-containerd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.Enable("faasd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.Start("faas-containerd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = systemd.Start("faasd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func binExists(folder, name string) error {
|
||||||
|
findPath := path.Join(folder, name)
|
||||||
|
if _, err := os.Stat(findPath); err != nil {
|
||||||
|
return fmt.Errorf("unable to stat %s, install this binary before continuing", findPath)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -22,6 +22,7 @@ const WelcomeMessage = "Welcome to faasd"
|
|||||||
func init() {
|
func init() {
|
||||||
rootCommand.AddCommand(versionCmd)
|
rootCommand.AddCommand(versionCmd)
|
||||||
rootCommand.AddCommand(upCmd)
|
rootCommand.AddCommand(upCmd)
|
||||||
|
rootCommand.AddCommand(installCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootCommand = &cobra.Command{
|
var rootCommand = &cobra.Command{
|
||||||
|
79
cmd/up.go
79
cmd/up.go
@ -1,9 +1,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path"
|
"path"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alexellis/faasd/pkg"
|
"github.com/alexellis/faasd/pkg"
|
||||||
@ -18,8 +22,57 @@ var upCmd = &cobra.Command{
|
|||||||
|
|
||||||
func runUp(_ *cobra.Command, _ []string) error {
|
func runUp(_ *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
|
services := makeServiceDefinitions()
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
supervisor, err := pkg.NewSupervisor("/run/containerd/containerd.sock")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Supervisor created in: %s\n", time.Since(start).String())
|
||||||
|
|
||||||
|
start = time.Now()
|
||||||
|
|
||||||
|
err = supervisor.Start(services)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer supervisor.Close()
|
||||||
|
|
||||||
|
log.Printf("Supervisor init done in: %s\n", time.Since(start).String())
|
||||||
|
|
||||||
|
shutdownTimeout := time.Second * 1
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
|
||||||
|
log.Printf("faasd: waiting for SIGTERM or SIGINT\n")
|
||||||
|
<-sig
|
||||||
|
|
||||||
|
log.Printf("Signal received.. shutting down server in %s\n", shutdownTimeout.String())
|
||||||
|
err := supervisor.Remove(services)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
time.AfterFunc(shutdownTimeout, func() {
|
||||||
|
wg.Done()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeServiceDefinitions() []pkg.Service {
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
svcs := []pkg.Service{
|
|
||||||
|
return []pkg.Service{
|
||||||
pkg.Service{
|
pkg.Service{
|
||||||
Name: "nats",
|
Name: "nats",
|
||||||
Env: []string{""},
|
Env: []string{""},
|
||||||
@ -71,28 +124,4 @@ func runUp(_ *cobra.Command, _ []string) error {
|
|||||||
Caps: []string{"CAP_NET_RAW"},
|
Caps: []string{"CAP_NET_RAW"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
supervisor, err := pkg.NewSupervisor("/run/containerd/containerd.sock")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Supervisor created in: %s\n", time.Since(start).String())
|
|
||||||
|
|
||||||
start = time.Now()
|
|
||||||
|
|
||||||
err = supervisor.Start(svcs)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer supervisor.Close()
|
|
||||||
|
|
||||||
log.Printf("Supervisor init done in: %s\n", time.Since(start).String())
|
|
||||||
|
|
||||||
time.Sleep(time.Minute * 120)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
12
hack/faas-containerd.service
Normal file
12
hack/faas-containerd.service
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=faasd-containerd
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
MemoryLimit=500M
|
||||||
|
ExecStart=/usr/local/bin/faas-containerd
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
WorkingDirectory=/usr/local/bin/
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
13
hack/faasd.service
Normal file
13
hack/faasd.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=faasd
|
||||||
|
After=faas-containerd.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
MemoryLimit=500M
|
||||||
|
ExecStart={{.Cwd}}/faasd up
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
WorkingDirectory={{.Cwd}}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -44,6 +44,18 @@ func (s *Supervisor) Close() {
|
|||||||
defer s.client.Close()
|
defer s.client.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Supervisor) Remove(svcs []Service) error {
|
||||||
|
ctx := namespaces.WithNamespace(context.Background(), "default")
|
||||||
|
|
||||||
|
for _, svc := range svcs {
|
||||||
|
err := removeContainer(ctx, s.client, svc.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Supervisor) Start(svcs []Service) error {
|
func (s *Supervisor) Start(svcs []Service) error {
|
||||||
ctx := namespaces.WithNamespace(context.Background(), "default")
|
ctx := namespaces.WithNamespace(context.Background(), "default")
|
||||||
|
|
||||||
@ -61,7 +73,7 @@ func (s *Supervisor) Start(svcs []Service) error {
|
|||||||
images := map[string]containerd.Image{}
|
images := map[string]containerd.Image{}
|
||||||
|
|
||||||
for _, svc := range svcs {
|
for _, svc := range svcs {
|
||||||
fmt.Printf("Preparing: %s\n", svc.Name)
|
fmt.Printf("Preparing: %s with image: %s\n", svc.Name, svc.Image)
|
||||||
|
|
||||||
img, err := prepareImage(ctx, s.client, svc.Image)
|
img, err := prepareImage(ctx, s.client, svc.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,7 +82,6 @@ func (s *Supervisor) Start(svcs []Service) error {
|
|||||||
images[svc.Name] = img
|
images[svc.Name] = img
|
||||||
size, _ := img.Size(ctx)
|
size, _ := img.Size(ctx)
|
||||||
fmt.Printf("Prepare done for: %s, %d bytes\n", svc.Image, size)
|
fmt.Printf("Prepare done for: %s, %d bytes\n", svc.Image, size)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, svc := range svcs {
|
for _, svc := range svcs {
|
||||||
@ -78,37 +89,9 @@ func (s *Supervisor) Start(svcs []Service) error {
|
|||||||
|
|
||||||
image := images[svc.Name]
|
image := images[svc.Name]
|
||||||
|
|
||||||
container, containerErr := s.client.LoadContainer(ctx, svc.Name)
|
containerErr := removeContainer(ctx, s.client, svc.Name)
|
||||||
|
if containerErr != nil {
|
||||||
if containerErr == nil {
|
return containerErr
|
||||||
found := true
|
|
||||||
t, err := container.Task(ctx, nil)
|
|
||||||
if err != nil {
|
|
||||||
if errdefs.IsNotFound(err) {
|
|
||||||
found = false
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("unable to get task %s: ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if found {
|
|
||||||
status, _ := t.Status(ctx)
|
|
||||||
fmt.Println("Status:", status.Status)
|
|
||||||
|
|
||||||
// if status.Status == containerd.Running {
|
|
||||||
log.Println("need to kill", svc.Name)
|
|
||||||
err := killTask(ctx, t)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), svc.Name, err)
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
err = container.Delete(ctx, containerd.WithSnapshotCleanup)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), svc.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts := []specs.Mount{}
|
mounts := []specs.Mount{}
|
||||||
@ -185,7 +168,7 @@ func (s *Supervisor) Start(svcs []Service) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip := getIP(container.ID(), task.Pid())
|
ip := getIP(newContainer.ID(), task.Pid())
|
||||||
|
|
||||||
hosts, _ := ioutil.ReadFile("hosts")
|
hosts, _ := ioutil.ReadFile("hosts")
|
||||||
|
|
||||||
@ -324,3 +307,37 @@ func killTask(ctx context.Context, task containerd.Task) error {
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeContainer(ctx context.Context, client *containerd.Client, name string) error {
|
||||||
|
|
||||||
|
container, containerErr := client.LoadContainer(ctx, name)
|
||||||
|
|
||||||
|
if containerErr == nil {
|
||||||
|
found := true
|
||||||
|
t, err := container.Task(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
if errdefs.IsNotFound(err) {
|
||||||
|
found = false
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unable to get task %s: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
status, _ := t.Status(ctx)
|
||||||
|
fmt.Printf("Status of %s is: %s\n", name, status.Status)
|
||||||
|
|
||||||
|
log.Printf("Need to kill %s\n", name)
|
||||||
|
err := killTask(ctx, t)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
100
pkg/systemd/systemd.go
Normal file
100
pkg/systemd/systemd.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package systemd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
execute "github.com/alexellis/go-execute/pkg/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Enable(unit string) error {
|
||||||
|
task := execute.ExecTask{Command: "systemctl",
|
||||||
|
Args: []string{"enable", unit},
|
||||||
|
StreamStdio: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := task.Execute()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("error executing task %s %v, stderr: %s", task.Command, task.Args, res.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Start(unit string) error {
|
||||||
|
task := execute.ExecTask{Command: "systemctl",
|
||||||
|
Args: []string{"start", unit},
|
||||||
|
StreamStdio: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := task.Execute()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("error executing task %s %v, stderr: %s", task.Command, task.Args, res.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DaemonReload() error {
|
||||||
|
task := execute.ExecTask{Command: "systemctl",
|
||||||
|
Args: []string{"daemon-reload"},
|
||||||
|
StreamStdio: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := task.Execute()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("error executing task %s %v, stderr: %s", task.Command, task.Args, res.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstallUnit(name string) error {
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles("./hack/" + name + ".service")
|
||||||
|
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
var tpl bytes.Buffer
|
||||||
|
userData := struct {
|
||||||
|
Cwd string
|
||||||
|
}{
|
||||||
|
Cwd: wd,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.Execute(&tpl, userData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = writeUnit(name+".service", tpl.Bytes())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeUnit(name string, data []byte) error {
|
||||||
|
f, err := os.Create(filepath.Join("/lib/systemd/system", name))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = f.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
Reference in New Issue
Block a user