105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package docker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
dockerTypes "github.com/docker/docker/api/types"
|
|
"github.com/metrue/fx/constants"
|
|
containerruntimes "github.com/metrue/fx/container_runtimes"
|
|
dockerHTTP "github.com/metrue/fx/container_runtimes/docker/http"
|
|
dockerSDK "github.com/metrue/fx/container_runtimes/docker/sdk"
|
|
"github.com/metrue/fx/deploy"
|
|
"github.com/metrue/fx/packer"
|
|
"github.com/metrue/fx/types"
|
|
"github.com/metrue/fx/utils"
|
|
)
|
|
|
|
// Docker manage container
|
|
type Docker struct {
|
|
cli containerruntimes.ContainerRuntime
|
|
}
|
|
|
|
// CreateClient create a docker instance
|
|
func CreateClient(ctx context.Context) (d *Docker, err error) {
|
|
var cli containerruntimes.ContainerRuntime
|
|
host := os.Getenv("DOCKER_REMOTE_HOST_ADDR")
|
|
user := os.Getenv("DOCKER_REMOTE_HOST_USER")
|
|
if host != "" && user != "" {
|
|
cli, err = dockerHTTP.Create(host, constants.AgentPort)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
cli, err = dockerSDK.CreateClient(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &Docker{cli: cli}, nil
|
|
}
|
|
|
|
// Deploy create a Docker container from given image, and bind the constants.FxContainerExposePort to given port
|
|
func (d *Docker) Deploy(ctx context.Context, fn types.Func, name string, ports []types.PortBinding) error {
|
|
workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix())
|
|
defer os.RemoveAll(workdir)
|
|
|
|
if err := packer.PackIntoDir(fn, workdir); err != nil {
|
|
log.Fatalf("could not pack function %v: %v", fn, err)
|
|
return err
|
|
}
|
|
|
|
if err := d.cli.BuildImage(ctx, workdir, name); err != nil {
|
|
log.Fatalf("could not build image: %v", err)
|
|
return err
|
|
}
|
|
|
|
nameWithTag := name + ":latest"
|
|
if err := d.cli.TagImage(ctx, name, nameWithTag); err != nil {
|
|
log.Fatalf("could not tag image: %v", err)
|
|
return err
|
|
}
|
|
|
|
// when deploy a function on a bare Docker running without Kubernetes,
|
|
// image would be built on-demand on host locally, so there is no need to
|
|
// pull image from remote.
|
|
// But it takes some times waiting image ready after image built, we retry to make sure it ready here
|
|
var imgInfo dockerTypes.ImageInspect
|
|
if err := utils.RunWithRetry(func() error {
|
|
return d.cli.InspectImage(ctx, name, &imgInfo)
|
|
}, time.Second*1, 5); err != nil {
|
|
return err
|
|
}
|
|
|
|
return d.cli.StartContainer(ctx, name, name, ports)
|
|
}
|
|
|
|
// Update a container
|
|
func (d *Docker) Update(ctx context.Context, name string) error {
|
|
return nil
|
|
}
|
|
|
|
// Destroy stop and remove container
|
|
func (d *Docker) Destroy(ctx context.Context, name string) error {
|
|
return d.cli.StopContainer(ctx, name)
|
|
}
|
|
|
|
// GetStatus get status of container
|
|
func (d *Docker) GetStatus(ctx context.Context, name string) error {
|
|
return nil
|
|
}
|
|
|
|
// List services
|
|
func (d *Docker) List(ctx context.Context, name string) ([]types.Service, error) {
|
|
// FIXME support remote host
|
|
return d.cli.ListContainer(ctx, name)
|
|
}
|
|
|
|
var (
|
|
_ deploy.Deployer = &Docker{}
|
|
)
|