mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-18 12:06:36 +00:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
d19d8998d8 | |||
376c8e5d7b | |||
3ee52c6ed7 | |||
da16bdeee8 |
10
Gopkg.lock
generated
10
Gopkg.lock
generated
@ -37,6 +37,14 @@
|
|||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "9e921883ac929bbe515b39793ece99ce3a9d7706"
|
revision = "9e921883ac929bbe515b39793ece99ce3a9d7706"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:74860eb071d52337d67e9ffd6893b29affebd026505aa917ec23131576a91a77"
|
||||||
|
name = "github.com/alexellis/go-execute"
|
||||||
|
packages = ["pkg/v1"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "961405ea754427780f2151adff607fa740d377f7"
|
||||||
|
version = "0.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:386ca0ac781cc1b630b3ed21725759770174140164b3faf3810e6ed6366a970b"
|
digest = "1:386ca0ac781cc1b630b3ed21725759770174140164b3faf3810e6ed6366a970b"
|
||||||
name = "github.com/containerd/containerd"
|
name = "github.com/containerd/containerd"
|
||||||
@ -440,7 +448,7 @@
|
|||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
input-imports = [
|
||||||
"github.com/alexellis/go-execute",
|
"github.com/alexellis/go-execute/pkg/v1",
|
||||||
"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",
|
||||||
|
@ -63,21 +63,21 @@ go build && sudo ./faasd
|
|||||||
Or get from binaries:
|
Or get from binaries:
|
||||||
|
|
||||||
|
|
||||||
### Build and run faas-containerd
|
### Build and run
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# For x86_64
|
# For x86_64
|
||||||
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.1.3/faasd" \
|
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.1/faasd" \
|
||||||
-o "/usr/local/bin/faasd" \
|
-o "/usr/local/bin/faasd" \
|
||||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||||
|
|
||||||
# armhf
|
# armhf
|
||||||
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.1.3/faasd-armhf" \
|
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.1/faasd-armhf" \
|
||||||
-o "/usr/local/bin/faasd" \
|
-o "/usr/local/bin/faasd" \
|
||||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||||
|
|
||||||
# arm64
|
# arm64
|
||||||
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.1.3/faasd-arm64" \
|
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.1/faasd-arm64" \
|
||||||
-o "/usr/local/bin/faasd" \
|
-o "/usr/local/bin/faasd" \
|
||||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||||
```
|
```
|
||||||
|
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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
21
vendor/github.com/alexellis/go-execute/LICENSE
generated
vendored
Normal file
21
vendor/github.com/alexellis/go-execute/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Inlets
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
117
vendor/github.com/alexellis/go-execute/pkg/v1/exec.go
generated
vendored
Normal file
117
vendor/github.com/alexellis/go-execute/pkg/v1/exec.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package execute
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExecTask struct {
|
||||||
|
Command string
|
||||||
|
Args []string
|
||||||
|
Shell bool
|
||||||
|
Env []string
|
||||||
|
Cwd string
|
||||||
|
|
||||||
|
// StreamStdio prints stdout and stderr directly to os.Stdout/err as
|
||||||
|
// the command runs.
|
||||||
|
StreamStdio bool
|
||||||
|
|
||||||
|
// PrintCommand prints the command before executing
|
||||||
|
PrintCommand bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecResult struct {
|
||||||
|
Stdout string
|
||||||
|
Stderr string
|
||||||
|
ExitCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (et ExecTask) Execute() (ExecResult, error) {
|
||||||
|
argsSt := ""
|
||||||
|
if len(et.Args) > 0 {
|
||||||
|
argsSt = strings.Join(et.Args, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if et.PrintCommand {
|
||||||
|
fmt.Println("exec: ", et.Command, argsSt)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
|
||||||
|
if et.Shell {
|
||||||
|
var args []string
|
||||||
|
if len(et.Args) == 0 {
|
||||||
|
startArgs := strings.Split(et.Command, " ")
|
||||||
|
script := strings.Join(startArgs, " ")
|
||||||
|
args = append([]string{"-c"}, fmt.Sprintf("%s", script))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
script := strings.Join(et.Args, " ")
|
||||||
|
args = append([]string{"-c"}, fmt.Sprintf("%s %s", et.Command, script))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = exec.Command("/bin/bash", args...)
|
||||||
|
} else {
|
||||||
|
if strings.Index(et.Command, " ") > 0 {
|
||||||
|
parts := strings.Split(et.Command, " ")
|
||||||
|
command := parts[0]
|
||||||
|
args := parts[1:]
|
||||||
|
cmd = exec.Command(command, args...)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(et.Command, et.Args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Dir = et.Cwd
|
||||||
|
|
||||||
|
if len(et.Env) > 0 {
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
for _, env := range et.Env {
|
||||||
|
cmd.Env = append(cmd.Env, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stdoutBuff := bytes.Buffer{}
|
||||||
|
stderrBuff := bytes.Buffer{}
|
||||||
|
|
||||||
|
var stdoutWriters io.Writer
|
||||||
|
var stderrWriters io.Writer
|
||||||
|
|
||||||
|
if et.StreamStdio {
|
||||||
|
stdoutWriters = io.MultiWriter(os.Stdout, &stdoutBuff)
|
||||||
|
stderrWriters = io.MultiWriter(os.Stderr, &stderrBuff)
|
||||||
|
} else {
|
||||||
|
stdoutWriters = &stdoutBuff
|
||||||
|
stderrWriters = &stderrBuff
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Stdout = stdoutWriters
|
||||||
|
cmd.Stderr = stderrWriters
|
||||||
|
|
||||||
|
startErr := cmd.Start()
|
||||||
|
|
||||||
|
if startErr != nil {
|
||||||
|
return ExecResult{}, startErr
|
||||||
|
}
|
||||||
|
|
||||||
|
exitCode := 0
|
||||||
|
execErr := cmd.Wait()
|
||||||
|
if execErr != nil {
|
||||||
|
if exitError, ok := execErr.(*exec.ExitError); ok {
|
||||||
|
|
||||||
|
exitCode = exitError.ExitCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExecResult{
|
||||||
|
Stdout: string(stdoutBuff.Bytes()),
|
||||||
|
Stderr: string(stderrBuff.Bytes()),
|
||||||
|
ExitCode: exitCode,
|
||||||
|
}, nil
|
||||||
|
}
|
Reference in New Issue
Block a user