Compare commits

..

3 Commits

Author SHA1 Message Date
294ef0f17f Fix error handling
An error could be thrown here if the status was nil

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2021-01-04 11:19:37 +00:00
32c00f0e9e Use the openfaas namespace for core services
All services like docker and k8s.io use their own namespaces
for core services, this change moves openfaas services into
the openfaas namespace instead of the default one.

The main change is that logs will look like:

journalctl -t openfaas:gateway

Instead of "default:gateway"

Function logs will remain unaffected and scheduled in the
openfaas-fn namespace.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2021-01-04 10:54:12 +00:00
2533c065bf Add user support for custom containers
Custom containers in the compose file can have a directory
mounted to store state for things like a database. This requires
a specific user since influxdb/postgresql and other containers
create folders and update permissions on start-up.

Tested with influxdb on Ubuntu with userid 1000, which failed
before the change.

Adds a grace period in the e2e tests.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2021-01-04 09:55:37 +00:00
5 changed files with 64 additions and 31 deletions

View File

@ -62,4 +62,5 @@ test-e2e:
sleep 3
/usr/local/bin/faas-cli list
sleep 3
/usr/local/bin/faas-cli logs figlet --follow=false | grep Forking
journalctl -t openfaas-fn:figlet --no-pager
/usr/local/bin/faas-cli logs figlet --since 15m --follow=false | grep Forking

View File

@ -125,14 +125,16 @@ echo logs | faas-cli invoke figlet
Core services as defined in the docker-compose.yaml file are deployed as containers by faasd.
The namespace is `openfaas` for core services.
View the logs for a component by giving its NAME:
```bash
journalctl -t default:NAME
journalctl -t openfaas:NAME
journalctl -t default:gateway
journalctl -t openfaas:gateway
journalctl -t default:queue-worker
journalctl -t openfaas:queue-worker
```
You can also use `-f` to follow the logs, or `--lines` to tail a number of lines, or `--since` to give a timeframe.

View File

@ -3,4 +3,11 @@ package pkg
const (
// FunctionNamespace is the default containerd namespace functions are created
FunctionNamespace = "openfaas-fn"
// faasdNamespace is the containerd namespace services are created
faasdNamespace = "openfaas"
faasServicesPullAlways = false
defaultSnapshotter = "overlayfs"
)

View File

@ -27,31 +27,34 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
container, containerErr := client.LoadContainer(ctx, name)
if containerErr == nil {
found := true
taskFound := true
t, err := container.Task(ctx, nil)
if err != nil {
if errdefs.IsNotFound(err) {
found = false
taskFound = 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 taskFound {
status, err := t.Status(ctx)
if err != nil {
log.Printf("Unable to get status for: %s, error: %s", name, err.Error())
} else {
log.Printf("Status of %s is: %s\n", name, status.Status)
}
log.Printf("Need to kill task: %s\n", name)
if err = killTask(ctx, t); err != nil {
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), name, err)
}
}
err = container.Delete(ctx, containerd.WithSnapshotCleanup)
if err != nil {
if err := container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), name, err)
}
} else {
service := client.SnapshotService("")
key := name + "snapshot"
@ -70,6 +73,7 @@ func killTask(ctx context.Context, task containerd.Task) error {
wg := &sync.WaitGroup{}
wg.Add(1)
var err error
go func() {
defer wg.Done()
if task != nil {
@ -114,6 +118,7 @@ func getResolver(ctx context.Context, configFile *configfile.ConfigFile) (remote
}
return ac.Username, ac.Password, nil
}
authOpts := []docker.AuthorizerOpt{docker.WithAuthCreds(credFunc)}
authorizer := docker.NewDockerAuthorizer(authOpts...)
opts := docker.ResolverOptions{
@ -128,7 +133,7 @@ func PrepareImage(ctx context.Context, client *containerd.Client, imageName, sna
resolver remotes.Resolver
)
if _, stErr := os.Stat(filepath.Join(dockerConfigDir, config.ConfigFileName)); stErr == nil {
if _, statErr := os.Stat(filepath.Join(dockerConfigDir, config.ConfigFileName)); statErr == nil {
configFile, err := config.Load(dockerConfigDir)
if err != nil {
return nil, err
@ -137,8 +142,8 @@ func PrepareImage(ctx context.Context, client *containerd.Client, imageName, sna
if err != nil {
return empty, err
}
} else if !os.IsNotExist(stErr) {
return empty, stErr
} else if !os.IsNotExist(statErr) {
return empty, statErr
}
var image containerd.Image
@ -150,7 +155,6 @@ func PrepareImage(ctx context.Context, client *containerd.Client, imageName, sna
image = img
} else {
img, err := client.GetImage(ctx, imageName)
if err != nil {
if !errdefs.IsNotFound(err) {
@ -187,9 +191,11 @@ func pullImage(ctx context.Context, client *containerd.Client, resolver remotes.
rOpts := []containerd.RemoteOpt{
containerd.WithPullUnpack,
}
if resolver != nil {
rOpts = append(rOpts, containerd.WithResolver(resolver))
}
img, err := client.Pull(ctx, imageName, rOpts...)
if err != nil {
return empty, fmt.Errorf("cannot pull: %s", err)

View File

@ -26,14 +26,11 @@ import (
)
const (
defaultSnapshotter = "overlayfs"
workingDirectoryPermission = 0644
// faasdNamespace is the containerd namespace services are created
faasdNamespace = "default"
faasServicesPullAlways = false
)
type Service struct {
// Image is the container image registry reference, in an OCI format.
Image string
Env []string
Name string
@ -42,6 +39,10 @@ type Service struct {
Args []string
DependsOn []string
Ports []ServicePort
// User in the docker-compose.yaml spec can set as follows:
// a user-id, username, userid:groupid or user:group
User string
}
type ServicePort struct {
@ -161,12 +162,17 @@ func (s *Supervisor) Start(svcs []Service) error {
Options: []string{"rbind", "ro"},
})
if len(svc.User) > 0 {
log.Printf("Running %s with user: %q", svc.Name, svc.User)
}
newContainer, err := s.client.NewContainer(
ctx,
svc.Name,
containerd.WithImage(image),
containerd.WithNewSnapshot(svc.Name+"-snapshot", image),
containerd.WithNewSpec(oci.WithImageConfig(image),
withUserOrDefault(svc.User),
oci.WithCapabilities(svc.Caps),
oci.WithMounts(mounts),
withOCIArgs(svc.Args),
@ -201,21 +207,21 @@ func (s *Supervisor) Start(svcs []Service) error {
log.Printf("%s has IP: %s\n", newContainer.ID(), ip.String())
hosts, _ := ioutil.ReadFile("hosts")
hosts, err := ioutil.ReadFile("hosts")
if err != nil {
log.Printf("Unable to read hosts file: %s\n", err.Error())
}
hosts = []byte(string(hosts) + fmt.Sprintf(`
%s %s
`, ip, svc.Name))
writeErr := ioutil.WriteFile("hosts", hosts, workingDirectoryPermission)
if writeErr != nil {
log.Printf("Error writing file %s %s\n", "hosts", writeErr)
if err := ioutil.WriteFile("hosts", hosts, workingDirectoryPermission); err != nil {
log.Printf("Error writing file: %s %s\n", "hosts", err)
}
// os.Chown("hosts", 101, 101)
_, err = task.Wait(ctx)
if err != nil {
log.Printf("Wait err: %s\n", err)
if _, err := task.Wait(ctx); err != nil {
log.Printf("Task wait error: %s\n", err)
return err
}
@ -223,7 +229,7 @@ func (s *Supervisor) Start(svcs []Service) error {
// log.Println("Exited: ", exitStatusC)
if err = task.Start(ctx); err != nil {
log.Printf("Task err: %s\n", err)
log.Printf("Task start error: %s\n", err)
return err
}
}
@ -253,6 +259,16 @@ func (s *Supervisor) Remove(svcs []Service) error {
return nil
}
func withUserOrDefault(userstr string) oci.SpecOpts {
if len(userstr) > 0 {
return oci.WithUser(userstr)
}
return func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
return nil
}
}
func withOCIArgs(args []string) oci.SpecOpts {
if len(args) > 0 {
return oci.WithProcessArgs(args...)
@ -305,6 +321,7 @@ func ParseCompose(config *compose.Config) ([]Service, error) {
Env: env,
Mounts: mounts,
DependsOn: s.DependsOn,
User: s.User,
Ports: convertPorts(s.Ports),
}
}