Compare commits

..

4 Commits
0.9.0 ... 0.9.2

Author SHA1 Message Date
5b92e7793d Move graph logic into package
Graph logic moves into depgraph package and makes internal
fields inaccessible. Completes feedback from @LucasRoesler
from previous PR where the dependency graph was added for 0.9.1

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2020-06-17 14:33:58 +01:00
88f1aa0433 Update docs for Graph and Node
Updates godoc and adds Add() method instead of using
append on the private slice.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2020-06-17 13:40:09 +01:00
2b9efd29a0 Add depends_on field for core service ordering
* Adds depends_on fields to compose YAML
* Updates parsing code to copy across depends_on field to
openfaas service from compose service definition
* Adds algorithm and unit tests for finding order
* Applies order to up.go command
* Makes unit testing on MacOS possible through build directives

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2020-06-17 13:40:09 +01:00
db5312158c Update cloud-config example to 0.9.0 2020-06-10 20:36:53 +01:00
12 changed files with 579 additions and 99 deletions

View File

@ -16,13 +16,13 @@ runcmd:
- mkdir -p /opt/cni/bin
- curl -sSL https://github.com/containernetworking/plugins/releases/download/v0.8.5/cni-plugins-linux-amd64-v0.8.5.tgz | tar -xz -C /opt/cni/bin
- mkdir -p /go/src/github.com/openfaas/
- cd /go/src/github.com/openfaas/ && git clone https://github.com/openfaas/faasd
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.8.2/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
- cd /go/src/github.com/openfaas/ && git clone https://github.com/openfaas/faasd && git checkout 0.9.0
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.9.0/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
- cd /go/src/github.com/openfaas/faasd/ && /usr/local/bin/faasd install
- systemctl status -l containerd --no-pager
- journalctl -u faasd-provider --no-pager
- systemctl status -l faasd-provider --no-pager
- systemctl status -l faasd --no-pager
- curl -sSLf https://cli.openfaas.com | sh
- sleep 5 && journalctl -u faasd --no-pager
- sleep 60 && journalctl -u faasd --no-pager
- cat /var/lib/faasd/secrets/basic-auth-password | /usr/local/bin/faas-cli login --password-stdin

View File

@ -17,6 +17,7 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
nats:
image: docker.io/library/nats-streaming:0.11.2
command:
@ -25,6 +26,7 @@ services:
- "8222"
- "--store=memory"
- "--cluster_id=faas-cluster"
prometheus:
image: docker.io/prom/prometheus:v2.14.0
volumes:
@ -33,6 +35,7 @@ services:
target: /etc/prometheus/prometheus.yml
cap_add:
- CAP_NET_RAW
gateway:
image: "docker.io/openfaas/gateway:0.18.17${ARCH_SUFFIX}"
environment:
@ -58,6 +61,11 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
depends_on:
- basic-auth-plugin
- nats
- prometheus
queue-worker:
image: docker.io/openfaas/queue-worker:0.11.2
environment:
@ -80,3 +88,5 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
depends_on:
- nats

View File

@ -18,19 +18,6 @@ type Dev struct {
CIDRs []*net.IPNet `json:"CIDRs,omitempty"`
}
func linkToNetDev(link netlink.Link) (Dev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return Dev{}, err
}
netDev := Dev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
return netDev, nil
}
// ConnectedToBridgeVethPeerIds returns peer indexes of veth links connected to
// the given bridge. The peer index is used to query from a container netns
// whether the container is connected to the bridge.

View File

@ -0,0 +1,19 @@
// +build linux
package cninetwork
import "github.com/vishvananda/netlink"
func linkToNetDev(link netlink.Link) (Dev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return Dev{}, err
}
netDev := Dev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
return netDev, nil
}

View File

@ -0,0 +1,10 @@
// +build darwin
package cninetwork
import "github.com/vishvananda/netlink"
func linkToNetDev(link netlink.Link) (Dev, error) {
return Dev{}, nil
}

106
pkg/depgraph/depgraph.go Normal file
View File

@ -0,0 +1,106 @@
package depgraph
import "log"
// Node represents a node in a Graph with
// 0 to many edges
type Node struct {
Name string
Edges []*Node
}
// Graph is a collection of nodes
type Graph struct {
nodes []*Node
}
func NewDepgraph() *Graph {
return &Graph{
nodes: []*Node{},
}
}
// Nodes returns the nodes within the graph
func (g *Graph) Nodes() []*Node {
return g.nodes
}
// Contains returns true if the target Node is found
// in its list
func (g *Graph) Contains(target *Node) bool {
for _, g := range g.nodes {
if g.Name == target.Name {
return true
}
}
return false
}
// Add places a Node into the current Graph
func (g *Graph) Add(target *Node) {
g.nodes = append(g.nodes, target)
}
// Remove deletes a target Node reference from the
// list of nodes in the graph
func (g *Graph) Remove(target *Node) {
var found *int
for i, n := range g.nodes {
if n == target {
found = &i
break
}
}
if found != nil {
g.nodes = append(g.nodes[:*found], g.nodes[*found+1:]...)
}
}
// Resolve retruns a list of node names in order of their dependencies.
// A use case may be for determining the correct order to install
// software packages, or to start services.
// Based upon the algorithm described by Ferry Boender in the following article
// https://www.electricmonk.nl/log/2008/08/07/dependency-resolving-algorithm/
func (g *Graph) Resolve() []string {
resolved := &Graph{}
unresolved := &Graph{}
for _, node := range g.nodes {
resolve(node, resolved, unresolved)
}
order := []string{}
for _, node := range resolved.Nodes() {
order = append(order, node.Name)
}
return order
}
// resolve mutates the resolved graph for a given starting
// node. The unresolved graph is used to detect a circular graph
// error and will throw a panic. This can be caught with a resolve
// in a go routine.
func resolve(node *Node, resolved, unresolved *Graph) {
unresolved.Add(node)
for _, edge := range node.Edges {
if !resolved.Contains(edge) && unresolved.Contains(edge) {
log.Panicf("edge: %s may be a circular dependency", edge.Name)
}
resolve(edge, resolved, unresolved)
}
for _, r := range resolved.nodes {
if r.Name == node.Name {
return
}
}
resolved.Add(node)
unresolved.Remove(node)
}

View File

@ -0,0 +1,41 @@
package depgraph
import "testing"
func Test_RemoveMedial(t *testing.T) {
g := Graph{nodes: []*Node{}}
a := &Node{Name: "A"}
b := &Node{Name: "B"}
c := &Node{Name: "C"}
g.nodes = append(g.nodes, a)
g.nodes = append(g.nodes, b)
g.nodes = append(g.nodes, c)
g.Remove(b)
for _, n := range g.nodes {
if n.Name == b.Name {
t.Fatalf("Found deleted node: %s", n.Name)
}
}
}
func Test_RemoveFinal(t *testing.T) {
g := Graph{nodes: []*Node{}}
a := &Node{Name: "A"}
b := &Node{Name: "B"}
c := &Node{Name: "C"}
g.nodes = append(g.nodes, a)
g.nodes = append(g.nodes, b)
g.nodes = append(g.nodes, c)
g.Remove(c)
for _, n := range g.nodes {
if n.Name == c.Name {
t.Fatalf("Found deleted node: %s", c.Name)
}
}
}

41
pkg/deployment_order.go Normal file
View File

@ -0,0 +1,41 @@
package pkg
import (
"log"
"github.com/openfaas/faasd/pkg/depgraph"
)
func buildDeploymentOrder(svcs []Service) []string {
graph := buildServiceGraph(svcs)
order := graph.Resolve()
log.Printf("Start-up order:\n")
for _, node := range order {
log.Printf("- %s\n", node)
}
return order
}
func buildServiceGraph(svcs []Service) *depgraph.Graph {
graph := depgraph.NewDepgraph()
nodeMap := map[string]*depgraph.Node{}
for _, s := range svcs {
n := &depgraph.Node{Name: s.Name}
nodeMap[s.Name] = n
graph.Add(n)
}
for _, s := range svcs {
for _, d := range s.DependsOn {
nodeMap[s.Name].Edges = append(nodeMap[s.Name].Edges, nodeMap[d])
}
}
return graph
}

View File

@ -0,0 +1,224 @@
package pkg
import (
"log"
"testing"
)
func Test_buildDeploymentOrder_ARequiresB(t *testing.T) {
svcs := []Service{
{
Name: "A",
DependsOn: []string{"B"},
},
{
Name: "B",
DependsOn: []string{},
},
}
order := buildDeploymentOrder(svcs)
if len(order) < len(svcs) {
t.Fatalf("length of order too short: %d", len(order))
}
got := order[0]
want := "B"
if got != want {
t.Fatalf("%s should be last to be installed, but was: %s", want, got)
}
}
func Test_buildDeploymentOrder_ARequiresBAndC(t *testing.T) {
svcs := []Service{
{
Name: "A",
DependsOn: []string{"B", "C"},
},
{
Name: "B",
DependsOn: []string{},
},
{
Name: "C",
DependsOn: []string{},
},
}
order := buildDeploymentOrder(svcs)
if len(order) < len(svcs) {
t.Fatalf("length of order too short: %d", len(order))
}
a := indexStr(order, "a")
b := indexStr(order, "b")
c := indexStr(order, "c")
if a > b {
t.Fatalf("a should be after dependencies")
}
if a > c {
t.Fatalf("a should be after dependencies")
}
}
func Test_buildDeploymentOrder_ARequiresBRequiresC(t *testing.T) {
svcs := []Service{
{
Name: "A",
DependsOn: []string{"B"},
},
{
Name: "B",
DependsOn: []string{"C"},
},
{
Name: "C",
DependsOn: []string{},
},
}
order := buildDeploymentOrder(svcs)
if len(order) < len(svcs) {
t.Fatalf("length of order too short: %d", len(order))
}
got := order[0]
want := "C"
if got != want {
t.Fatalf("%s should be last to be installed, but was: %s", want, got)
}
got = order[1]
want = "B"
if got != want {
t.Fatalf("%s should be last to be installed, but was: %s", want, got)
}
got = order[2]
want = "A"
if got != want {
t.Fatalf("%s should be last to be installed, but was: %s", want, got)
}
}
func Test_buildDeploymentOrderCircularARequiresBRequiresA(t *testing.T) {
svcs := []Service{
{
Name: "A",
DependsOn: []string{"B"},
},
{
Name: "B",
DependsOn: []string{"A"},
},
}
defer func() { recover() }()
buildDeploymentOrder(svcs)
t.Fatalf("did not panic as expected")
}
func Test_buildDeploymentOrderComposeFile(t *testing.T) {
// svcs := []Service{}
file, err := LoadComposeFileWithArch("../", "docker-compose.yaml", func() (string, string) {
return "x86_64", "Linux"
})
if err != nil {
t.Fatalf("unable to load compose file: %s", err)
}
svcs, err := ParseCompose(file)
if err != nil {
t.Fatalf("unable to parse compose file: %s", err)
}
for _, s := range svcs {
log.Printf("Service: %s\n", s.Name)
for _, d := range s.DependsOn {
log.Printf("Link: %s => %s\n", s.Name, d)
}
}
order := buildDeploymentOrder(svcs)
if len(order) < len(svcs) {
t.Fatalf("length of order too short: %d", len(order))
}
queueWorker := indexStr(order, "queue-worker")
nats := indexStr(order, "nats")
gateway := indexStr(order, "gateway")
prometheus := indexStr(order, "prometheus")
if prometheus > gateway {
t.Fatalf("Prometheus order was after gateway, and should be before")
}
if nats > gateway {
t.Fatalf("NATS order was after gateway, and should be before")
}
if nats > queueWorker {
t.Fatalf("NATS order was after queue-worker, and should be before")
}
}
func Test_buildDeploymentOrderOpenFaaS(t *testing.T) {
svcs := []Service{
{
Name: "queue-worker",
DependsOn: []string{"nats"},
},
{
Name: "prometheus",
DependsOn: []string{},
},
{
Name: "gateway",
DependsOn: []string{"prometheus", "nats", "basic-auth-plugin"},
},
{
Name: "basic-auth-plugin",
DependsOn: []string{},
},
{
Name: "nats",
DependsOn: []string{},
},
}
order := buildDeploymentOrder(svcs)
if len(order) < len(svcs) {
t.Fatalf("length of order too short: %d", len(order))
}
queueWorker := indexStr(order, "queue-worker")
nats := indexStr(order, "nats")
gateway := indexStr(order, "gateway")
prometheus := indexStr(order, "prometheus")
if prometheus > gateway {
t.Fatalf("Prometheus order was after gateway, and should be before")
}
if nats > gateway {
t.Fatalf("NATS order was after gateway, and should be before")
}
if nats > queueWorker {
t.Fatalf("NATS order was after queue-worker, and should be before")
}
}
func indexStr(st []string, t string) int {
for n, s := range st {
if s == t {
return n
}
}
return -1
}

View File

@ -34,12 +34,13 @@ const (
)
type Service struct {
Image string
Env []string
Name string
Mounts []Mount
Caps []string
Args []string
Image string
Env []string
Name string
Mounts []Mount
Caps []string
Args []string
DependsOn []string
}
type Mount struct {
@ -92,7 +93,7 @@ func (s *Supervisor) Start(svcs []Service) error {
images := map[string]containerd.Image{}
for _, svc := range svcs {
fmt.Printf("Preparing: %s with image: %s\n", svc.Name, svc.Image)
fmt.Printf("Preparing %s with image: %s\n", svc.Name, svc.Image)
img, err := service.PrepareImage(ctx, s.client, svc.Image, defaultSnapshotter, faasServicesPullAlways)
if err != nil {
@ -104,12 +105,26 @@ func (s *Supervisor) Start(svcs []Service) error {
}
for _, svc := range svcs {
fmt.Printf("Reconciling: %s\n", svc.Name)
fmt.Printf("Removing old container for: %s\n", svc.Name)
containerErr := service.Remove(ctx, s.client, svc.Name)
if containerErr != nil {
return containerErr
}
}
order := buildDeploymentOrder(svcs)
for _, key := range order {
var svc *Service
for _, s := range svcs {
if s.Name == key {
svc = &s
break
}
}
fmt.Printf("Starting: %s\n", svc.Name)
image := images[svc.Name]
@ -123,7 +138,6 @@ func (s *Supervisor) Start(svcs []Service) error {
Options: []string{"rbind", "rw"},
})
}
}
mounts = append(mounts, specs.Mount{
@ -153,11 +167,11 @@ func (s *Supervisor) Start(svcs []Service) error {
)
if containerCreateErr != nil {
log.Printf("Error creating container %s\n", containerCreateErr)
log.Printf("Error creating container: %s\n", containerCreateErr)
return containerCreateErr
}
log.Printf("Created container %s\n", newContainer.ID())
log.Printf("Created container: %s\n", newContainer.ID())
task, err := newContainer.NewTask(ctx, cio.NewCreator(cio.WithStdio))
if err != nil {
@ -176,6 +190,7 @@ func (s *Supervisor) Start(svcs []Service) error {
if err != nil {
return err
}
log.Printf("%s has IP: %s\n", newContainer.ID(), ip.String())
hosts, _ := ioutil.ReadFile("hosts")
@ -277,10 +292,11 @@ func ParseCompose(config *compose.Config) ([]Service, error) {
Name: s.Name,
Image: s.Image,
// ShellCommand is just an alias of string slice
Args: []string(s.Command),
Caps: s.CapAdd,
Env: env,
Mounts: mounts,
Args: []string(s.Command),
Caps: s.CapAdd,
Env: env,
Mounts: mounts,
DependsOn: s.DependsOn,
}
}
@ -289,6 +305,12 @@ func ParseCompose(config *compose.Config) ([]Service, error) {
// LoadComposeFile is a helper method for loading a docker-compose file
func LoadComposeFile(wd string, file string) (*compose.Config, error) {
return LoadComposeFileWithArch(wd, file, env.GetClientArch)
}
// LoadComposeFileWithArch is a helper method for loading a docker-compose file
func LoadComposeFileWithArch(wd string, file string, archGetter ArchGetter) (*compose.Config, error) {
file = path.Join(wd, file)
b, err := ioutil.ReadFile(file)
if err != nil {
@ -300,7 +322,7 @@ func LoadComposeFile(wd string, file string) (*compose.Config, error) {
return nil, err
}
archSuffix, err := GetArchSuffix(env.GetClientArch)
archSuffix, err := GetArchSuffix(archGetter)
if err != nil {
return nil, err
}

View File

@ -7,8 +7,10 @@ import (
)
func Test_ParseCompose(t *testing.T) {
wd := "testdata"
expected := map[string]Service{
want := map[string]Service{
"basic-auth-plugin": {
Name: "basic-auth-plugin",
Image: "docker.io/openfaas/basic-auth-plugin:0.18.17",
@ -73,7 +75,8 @@ func Test_ParseCompose(t *testing.T) {
Dest: path.Join("/run/secrets", "basic-auth-user"),
},
},
Caps: []string{"CAP_NET_RAW"},
Caps: []string{"CAP_NET_RAW"},
DependsOn: []string{"nats"},
},
"queue-worker": {
Name: "queue-worker",
@ -103,32 +106,39 @@ func Test_ParseCompose(t *testing.T) {
},
}
compose, err := LoadComposeFile(wd, "docker-compose.yaml")
compose, err := LoadComposeFileWithArch(wd, "docker-compose.yaml", func() (string, string) { return "x86_64", "Linux" })
if err != nil {
t.Fatalf("can not read docker-compose fixture: %s", err)
t.Fatalf("can't read docker-compose file: %s", err)
}
services, err := ParseCompose(compose)
if err != nil {
t.Fatalf("can not parse compose services: %s", err)
t.Fatalf("can't parse compose services: %s", err)
}
if len(services) != len(expected) {
t.Fatalf("expected: %d services, got: %d", len(expected), len(services))
if len(services) != len(want) {
t.Fatalf("want: %d services, got: %d", len(want), len(services))
}
for _, service := range services {
exp, ok := expected[service.Name]
exp, ok := want[service.Name]
if service.Name == "gateway" {
if len(service.DependsOn) == 0 {
t.Fatalf("gateway should have at least one depends_on entry")
}
}
if !ok {
t.Fatalf("unexpected service: %s", service.Name)
t.Fatalf("incorrect service: %s", service.Name)
}
if service.Name != exp.Name {
t.Fatalf("incorrect service Name:\n\texpected: %s,\n\tgot: %s", exp.Name, service.Name)
t.Fatalf("incorrect service Name:\n\twant: %s,\n\tgot: %s", exp.Name, service.Name)
}
if service.Image != exp.Image {
t.Fatalf("incorrect service Image:\n\texpected: %s,\n\tgot: %s", exp.Image, service.Image)
t.Fatalf("incorrect service Image:\n\twant: %s,\n\tgot: %s", exp.Image, service.Image)
}
equalStringSlice(t, exp.Env, service.Env)
@ -136,41 +146,41 @@ func Test_ParseCompose(t *testing.T) {
equalStringSlice(t, exp.Args, service.Args)
if !reflect.DeepEqual(exp.Mounts, service.Mounts) {
t.Fatalf("incorrect service Mounts:\n\texpected: %+v,\n\tgot: %+v", exp.Mounts, service.Mounts)
t.Fatalf("incorrect service Mounts:\n\twant: %+v,\n\tgot: %+v", exp.Mounts, service.Mounts)
}
}
}
func equalStringSlice(t *testing.T, expected, found []string) {
func equalStringSlice(t *testing.T, want, found []string) {
t.Helper()
if (expected == nil) != (found == nil) {
t.Fatalf("unexpected nil slice: expected %+v, got %+v", expected, found)
if (want == nil) != (found == nil) {
t.Fatalf("unexpected nil slice: want %+v, got %+v", want, found)
}
if len(expected) != len(found) {
t.Fatalf("unequal slice length: expected %+v, got %+v", expected, found)
if len(want) != len(found) {
t.Fatalf("unequal slice length: want %+v, got %+v", want, found)
}
for i := range expected {
if expected[i] != found[i] {
t.Fatalf("unexpected value at postition %d: expected %s, got %s", i, expected[i], found[i])
for i := range want {
if want[i] != found[i] {
t.Fatalf("unexpected value at postition %d: want %s, got %s", i, want[i], found[i])
}
}
}
func equalMountSlice(t *testing.T, expected, found []Mount) {
func equalMountSlice(t *testing.T, want, found []Mount) {
t.Helper()
if (expected == nil) != (found == nil) {
t.Fatalf("unexpected nil slice: expected %+v, got %+v", expected, found)
if (want == nil) != (found == nil) {
t.Fatalf("unexpected nil slice: want %+v, got %+v", want, found)
}
if len(expected) != len(found) {
t.Fatalf("unequal slice length: expected %+v, got %+v", expected, found)
if len(want) != len(found) {
t.Fatalf("unequal slice length: want %+v, got %+v", want, found)
}
for i := range expected {
if !reflect.DeepEqual(expected[i], found[i]) {
t.Fatalf("unexpected value at postition %d: expected %s, got %s", i, expected[i], found[i])
for i := range want {
if !reflect.DeepEqual(want[i], found[i]) {
t.Fatalf("unexpected value at postition %d: want %s, got %s", i, want[i], found[i])
}
}
}
@ -178,7 +188,7 @@ func equalMountSlice(t *testing.T, expected, found []Mount) {
func Test_GetArchSuffix(t *testing.T) {
cases := []struct {
name string
expected string
want string
foundArch string
foundOS string
err string
@ -192,37 +202,37 @@ func Test_GetArchSuffix(t *testing.T) {
name: "x86 has no suffix",
foundOS: "Linux",
foundArch: "x86_64",
expected: "",
want: "",
},
{
name: "unknown arch has no suffix",
foundOS: "Linux",
foundArch: "anything_else",
expected: "",
want: "",
},
{
name: "armhf has armhf suffix",
foundOS: "Linux",
foundArch: "armhf",
expected: "-armhf",
want: "-armhf",
},
{
name: "armv7l has armhf suffix",
foundOS: "Linux",
foundArch: "armv7l",
expected: "-armhf",
want: "-armhf",
},
{
name: "arm64 has arm64 suffix",
foundOS: "Linux",
foundArch: "arm64",
expected: "-arm64",
want: "-arm64",
},
{
name: "aarch64 has arm64 suffix",
foundOS: "Linux",
foundArch: "aarch64",
expected: "-arm64",
want: "-arm64",
},
}
@ -231,15 +241,15 @@ func Test_GetArchSuffix(t *testing.T) {
suffix, err := GetArchSuffix(testArchGetter(tc.foundArch, tc.foundOS))
if tc.err != "" && err == nil {
t.Fatalf("expected error %s but got nil", tc.err)
t.Fatalf("want error %s but got nil", tc.err)
} else if tc.err != "" && err.Error() != tc.err {
t.Fatalf("expected error %s, got %s", tc.err, err.Error())
t.Fatalf("want error %s, got %s", tc.err, err.Error())
} else if tc.err == "" && err != nil {
t.Fatalf("unexpected error %s", err.Error())
}
if suffix != tc.expected {
t.Fatalf("expected suffix %s, got %s", tc.expected, suffix)
if suffix != tc.want {
t.Fatalf("want suffix %s, got %s", tc.want, suffix)
}
})
}

View File

@ -1,12 +1,12 @@
version: "3.7"
services:
basic-auth-plugin:
image: docker.io/openfaas/basic-auth-plugin:0.18.17
image: "docker.io/openfaas/basic-auth-plugin:0.18.17${ARCH_SUFFIX}"
environment:
port: "8080"
secret_mount_path: "/run/secrets"
user_filename: "basic-auth-user"
pass_filename: "basic-auth-password"
- port=8080
- secret_mount_path=/run/secrets
- user_filename=basic-auth-user
- pass_filename=basic-auth-password
volumes:
# we assume cwd == /var/lib/faasd
- type: bind
@ -17,6 +17,7 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
nats:
image: docker.io/library/nats-streaming:0.11.2
command:
@ -25,6 +26,7 @@ services:
- "8222"
- "--store=memory"
- "--cluster_id=faas-cluster"
prometheus:
image: docker.io/prom/prometheus:v2.14.0
volumes:
@ -33,21 +35,22 @@ services:
target: /etc/prometheus/prometheus.yml
cap_add:
- CAP_NET_RAW
gateway:
image: docker.io/openfaas/gateway:0.18.17
image: "docker.io/openfaas/gateway:0.18.17${ARCH_SUFFIX}"
environment:
basic_auth: "true"
functions_provider_url: "http://faasd-provider:8081/"
direct_functions: "false"
read_timeout: "60s"
write_timeout: "60s"
upstream_timeout: "65s"
faas_nats_address: "nats"
faas_nats_port: "4222"
auth_proxy_url: "http://basic-auth-plugin:8080/validate"
auth_proxy_pass_body: "false"
secret_mount_path: "/run/secrets"
scale_from_zero: "true"
- basic_auth=true
- functions_provider_url=http://faasd-provider:8081/
- direct_functions=false
- read_timeout=60s
- write_timeout=60s
- upstream_timeout=65s
- faas_nats_address=nats
- faas_nats_port=4222
- auth_proxy_url=http://basic-auth-plugin:8080/validate
- auth_proxy_pass_body=false
- secret_mount_path=/run/secrets
- scale_from_zero=true
volumes:
# we assume cwd == /var/lib/faasd
- type: bind
@ -58,18 +61,23 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
depends_on:
- basic-auth-plugin
- nats
- prometheus
queue-worker:
image: docker.io/openfaas/queue-worker:0.11.2
environment:
faas_nats_address: "nats"
faas_nats_port: "4222"
gateway_invoke: "true"
faas_gateway_address: "gateway"
ack_wait: "5m5s"
max_inflight: "1"
write_debug: "false"
basic_auth: "true"
secret_mount_path: "/run/secrets"
- faas_nats_address=nats
- faas_nats_port=4222
- gateway_invoke=true
- faas_gateway_address=gateway
- ack_wait=5m5s
- max_inflight=1
- write_debug=false
- basic_auth=true
- secret_mount_path=/run/secrets
volumes:
# we assume cwd == /var/lib/faasd
- type: bind
@ -80,3 +88,5 @@ services:
target: /run/secrets/basic-auth-user
cap_add:
- CAP_NET_RAW
depends_on:
- nats