mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-18 20:16:36 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
6230d3504e | |||
4ba3ec3b64 | |||
ea9386d285 | |||
03500c5649 | |||
867f8459b0 | |||
6737712b28 | |||
832893998d | |||
1732566748 | |||
3b512f979c | |||
456e56342e | |||
d19d8998d8 | |||
376c8e5d7b |
19
Gopkg.lock
generated
19
Gopkg.lock
generated
@ -37,6 +37,22 @@
|
||||
pruneopts = "UT"
|
||||
revision = "9e921883ac929bbe515b39793ece99ce3a9d7706"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:74860eb071d52337d67e9ffd6893b29affebd026505aa917ec23131576a91a77"
|
||||
name = "github.com/alexellis/go-execute"
|
||||
packages = ["pkg/v1"]
|
||||
pruneopts = "UT"
|
||||
revision = "961405ea754427780f2151adff607fa740d377f7"
|
||||
version = "0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6076d857867a70e87dd1994407deb142f27436f1293b13e75cc053192d14eb0c"
|
||||
name = "github.com/alexellis/k3sup"
|
||||
packages = ["pkg/env"]
|
||||
pruneopts = "UT"
|
||||
revision = "f9a4adddc732742a9ee7962609408fb0999f2d7b"
|
||||
version = "0.7.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:386ca0ac781cc1b630b3ed21725759770174140164b3faf3810e6ed6366a970b"
|
||||
name = "github.com/containerd/containerd"
|
||||
@ -440,7 +456,8 @@
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/alexellis/go-execute",
|
||||
"github.com/alexellis/go-execute/pkg/v1",
|
||||
"github.com/alexellis/k3sup/pkg/env",
|
||||
"github.com/containerd/containerd",
|
||||
"github.com/containerd/containerd/cio",
|
||||
"github.com/containerd/containerd/containers",
|
||||
|
@ -10,6 +10,9 @@
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.5"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/alexellis/k3sup"
|
||||
version = "0.7.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/alexellis/go-execute"
|
||||
|
72
README.md
72
README.md
@ -24,64 +24,84 @@ You can use the standard [faas-cli](https://github.com/openfaas/faas-cli) with f
|
||||
* `faas describe`
|
||||
* `faas deploy --update=true --replace=false`
|
||||
* `faas invoke`
|
||||
* `faas invoke --async`
|
||||
|
||||
Other operations are pending development in the provider.
|
||||
|
||||
### Pre-reqs
|
||||
|
||||
* Linux - ideally Ubuntu, which is used for testing.
|
||||
* Linux - ideally Ubuntu, which is used for testing
|
||||
* Installation steps as per [faas-containerd](https://github.com/alexellis/faas-containerd) for building and for development
|
||||
* [netns](https://github.com/genuinetools/netns/releases) binary in `$PATH`
|
||||
* [containerd v1.3.2](https://github.com/containerd/containerd)
|
||||
* [faas-cli](https://github.com/openfaas/faas-cli) (optional)
|
||||
|
||||
## Backlog
|
||||
|
||||
* Use CNI to create network namespaces and adapters
|
||||
* Inject / manage IPs between core components for service to service communication - i.e. so Prometheus can scrape the OpenFaaS gateway
|
||||
* Monitor and restart any of the core components, if they crash
|
||||
* Configure `basic_auth` to protect the OpenFaaS gateway and faas-containerd HTTP API
|
||||
* Self-install / create systemd service on start-up using [go-systemd](https://github.com/coreos/go-systemd)
|
||||
* Bundle/package/automate installation of containerd - [see bootstrap from k3s](https://github.com/rancher/k3s)
|
||||
* Create [faasd.service](https://github.com/rancher/k3s/blob/master/k3s.service)
|
||||
Pending:
|
||||
|
||||
* [ ] Configure `basic_auth` to protect the OpenFaaS gateway and faas-containerd HTTP API
|
||||
* [ ] Use CNI to create network namespaces and adapters
|
||||
* [ ] Monitor and restart any of the core components at runtime if the container stops
|
||||
* [ ] Bundle/package/automate installation of containerd - [see bootstrap from k3s](https://github.com/rancher/k3s)
|
||||
* [ ] Provide ufw rules / example for blocking access to everything but a reverse proxy to the gateway container
|
||||
|
||||
## Hacking
|
||||
Done:
|
||||
|
||||
* [x] Inject / manage IPs between core components for service to service communication - i.e. so Prometheus can scrape the OpenFaaS gateway - done via `/etc/hosts` mount
|
||||
* [x] Add queue-worker and NATS
|
||||
* [x] Create faasd.service and faas-containerd.service
|
||||
* [x] Self-install / create systemd service via `faasd install`
|
||||
* [x] Restart containers upon restart of faasd
|
||||
* [x] Clear / remove containers and tasks with SIGTERM / SIGINT
|
||||
* [x] Determine armhf/arm64 containers to run for gateway
|
||||
|
||||
## Hacking (build from source)
|
||||
|
||||
First run faas-containerd
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src/github.com/alexellis/faas-containerd
|
||||
go build && sudo ./faas-containerd
|
||||
|
||||
# You'll need to install containerd and its pre-reqs first
|
||||
# https://github.com/alexellis/faas-containerd/
|
||||
|
||||
sudo ./faas-containerd
|
||||
```
|
||||
|
||||
Then run faasd, which brings up the gateway and Prometheus as containers
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src/github.com/alexellis/faasd
|
||||
go build && sudo ./faasd
|
||||
go build
|
||||
|
||||
# Install with systemd
|
||||
# sudo ./faasd install
|
||||
|
||||
# Or run interactively
|
||||
# sudo ./faasd up
|
||||
```
|
||||
|
||||
Or get from binaries:
|
||||
|
||||
|
||||
### Build and run faas-containerd
|
||||
### Build and run (binaries)
|
||||
|
||||
```sh
|
||||
# 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.2/faasd" \
|
||||
-o "/usr/local/bin/faasd" \
|
||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||
|
||||
# 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.2/faasd-armhf" \
|
||||
-o "/usr/local/bin/faasd" \
|
||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||
|
||||
# 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.2/faasd-arm64" \
|
||||
-o "/usr/local/bin/faasd" \
|
||||
&& sudo chmod a+x "/usr/local/bin/faasd"
|
||||
```
|
||||
|
||||
### At run-time
|
||||
|
||||
Look in `hosts` in the current working folder to get the IP for the gateway or Prometheus
|
||||
|
||||
@ -91,11 +111,25 @@ Look in `hosts` in the current working folder to get the IP for the gateway or P
|
||||
172.19.0.2 prometheus
|
||||
|
||||
172.19.0.3 gateway
|
||||
172.19.0.4 nats
|
||||
172.19.0.5 queue-worker
|
||||
```
|
||||
|
||||
Since faas-containerd uses containerd heavily it is not running as a container, but as a stand-alone process. Its port is available via the bridge interface, i.e. netns0.
|
||||
|
||||
Now go to the gateway's IP address as shown above on port 8080, i.e. http://172.19.0.3:8080 - you can also use this address to deploy OpenFaaS Functions via the `faas-cli`.
|
||||
* Prometheus will run on the Prometheus IP plus port 8080 i.e. http://172.19.0.2:9090/targets
|
||||
|
||||
* faas-containerd runs on 172.19.0.1:8081
|
||||
|
||||
* Now go to the gateway's IP address as shown above on port 8080, i.e. http://172.19.0.3:8080 - you can also use this address to deploy OpenFaaS Functions via the `faas-cli`.
|
||||
|
||||
#### Installation with systemd
|
||||
|
||||
* `faasd install` - install faasd and containerd with systemd
|
||||
* `journalctl -u faasd` - faasd systemd logs
|
||||
* `journalctl -u faas-containerd` - faas-containerd systemd logs
|
||||
|
||||
### Appendix
|
||||
|
||||
Removing containers:
|
||||
|
||||
|
@ -23,6 +23,11 @@ func runInstall(_ *cobra.Command, _ []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err := binExists("/usr/local/bin/", "faasd")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = binExists("/usr/local/bin/", "netns")
|
||||
if err != nil {
|
||||
return err
|
||||
|
28
cmd/up.go
28
cmd/up.go
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/alexellis/faasd/pkg"
|
||||
"github.com/alexellis/k3sup/pkg/env"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -22,7 +23,26 @@ var upCmd = &cobra.Command{
|
||||
|
||||
func runUp(_ *cobra.Command, _ []string) error {
|
||||
|
||||
services := makeServiceDefinitions()
|
||||
clientArch, clientOS := env.GetClientArch()
|
||||
|
||||
if clientOS != "Linux" {
|
||||
return fmt.Errorf("You can only use faasd on Linux")
|
||||
}
|
||||
clientSuffix := ""
|
||||
switch clientArch {
|
||||
case "x86_64":
|
||||
clientSuffix = ""
|
||||
break
|
||||
case "armhf":
|
||||
case "armv7l":
|
||||
clientSuffix = "-armhf"
|
||||
break
|
||||
case "arm64":
|
||||
case "aarch64":
|
||||
clientSuffix = "-arm64"
|
||||
}
|
||||
|
||||
services := makeServiceDefinitions(clientSuffix)
|
||||
|
||||
start := time.Now()
|
||||
supervisor, err := pkg.NewSupervisor("/run/containerd/containerd.sock")
|
||||
@ -69,7 +89,7 @@ func runUp(_ *cobra.Command, _ []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeServiceDefinitions() []pkg.Service {
|
||||
func makeServiceDefinitions(archSuffix string) []pkg.Service {
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
return []pkg.Service{
|
||||
@ -104,7 +124,7 @@ func makeServiceDefinitions() []pkg.Service {
|
||||
"faas_nats_address=nats",
|
||||
"faas_nats_port=4222",
|
||||
},
|
||||
Image: "docker.io/openfaas/gateway:0.18.7",
|
||||
Image: "docker.io/openfaas/gateway:0.18.8" + archSuffix,
|
||||
Mounts: []pkg.Mount{},
|
||||
Caps: []string{"CAP_NET_RAW"},
|
||||
},
|
||||
@ -117,7 +137,7 @@ func makeServiceDefinitions() []pkg.Service {
|
||||
"faas_gateway_address=gateway",
|
||||
"ack_wait=5m5s",
|
||||
"max_inflight=1",
|
||||
"faas_print_body=true",
|
||||
"write_debug=false",
|
||||
},
|
||||
Image: "docker.io/openfaas/queue-worker:0.9.0",
|
||||
Mounts: []pkg.Mount{},
|
||||
|
28
hack/build-containerd-armhf.sh
Executable file
28
hack/build-containerd-armhf.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Downloading Go"
|
||||
|
||||
curl -SLsf https://dl.google.com/go/go1.12.14.linux-armv6l.tar.gz > go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf go.tgz -C /usr/local/go/ --strip-components=1
|
||||
|
||||
export GOPATH=$HOME/go/
|
||||
export PATH=$PATH:/usr/local/go/bin/
|
||||
|
||||
go version
|
||||
|
||||
echo "Building containerd"
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/containerd
|
||||
cd $GOPATH/src/github.com/containerd
|
||||
git clone https://github.com/containerd/containerd
|
||||
|
||||
cd containerd
|
||||
git fetch origin --tags
|
||||
git checkout v1.3.2
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
sudo containerd --version
|
28
hack/build-containerd.sh
Normal file
28
hack/build-containerd.sh
Normal file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Downloading Go"
|
||||
|
||||
curl -SLsf https://dl.google.com/go/go1.12.14.linux-amd64.tar.gz > go.tgz
|
||||
sudo rm -rf /usr/local/go/
|
||||
sudo mkdir -p /usr/local/go/
|
||||
sudo tar -xvf go.tgz -C /usr/local/go/ --strip-components=1
|
||||
|
||||
export GOPATH=$HOME/go/
|
||||
export PATH=$PATH:/usr/local/go/bin/
|
||||
|
||||
go version
|
||||
|
||||
echo "Building containerd"
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/containerd
|
||||
cd $GOPATH/src/github.com/containerd
|
||||
git clone https://github.com/containerd/containerd
|
||||
|
||||
cd containerd
|
||||
git fetch origin --tags
|
||||
git checkout v1.3.2
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
sudo containerd --version
|
@ -4,7 +4,7 @@ After=faas-containerd.service
|
||||
|
||||
[Service]
|
||||
MemoryLimit=500M
|
||||
ExecStart={{.Cwd}}/faasd up
|
||||
ExecStart=/usr/local/bin/faasd up
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
WorkingDirectory={{.Cwd}}
|
||||
|
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
|
||||
}
|
21
vendor/github.com/alexellis/k3sup/LICENSE
generated
vendored
Normal file
21
vendor/github.com/alexellis/k3sup/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Alex Ellis
|
||||
|
||||
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.
|
29
vendor/github.com/alexellis/k3sup/pkg/env/env.go
generated
vendored
Normal file
29
vendor/github.com/alexellis/k3sup/pkg/env/env.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
execute "github.com/alexellis/go-execute/pkg/v1"
|
||||
)
|
||||
|
||||
// GetClientArch returns a pair of arch and os
|
||||
func GetClientArch() (string, string) {
|
||||
task := execute.ExecTask{Command: "uname", Args: []string{"-m"}}
|
||||
res, err := task.Execute()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
arch := strings.TrimSpace(res.Stdout)
|
||||
|
||||
taskOS := execute.ExecTask{Command: "uname", Args: []string{"-s"}}
|
||||
resOS, errOS := taskOS.Execute()
|
||||
if errOS != nil {
|
||||
log.Println(errOS)
|
||||
}
|
||||
|
||||
os := strings.TrimSpace(resOS.Stdout)
|
||||
|
||||
return arch, os
|
||||
}
|
Reference in New Issue
Block a user