158 lines
3.3 KiB
Go
158 lines
3.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"localenv/utils"
|
|
|
|
"github.com/docker/docker/api/types/swarm"
|
|
"github.com/docker/docker/client"
|
|
)
|
|
|
|
const NetworkName = "localenv"
|
|
|
|
var (
|
|
RetryServiceAttempts uint64 = 0
|
|
SwarmServiceReplicas uint64 = 1
|
|
|
|
RetryServiceDelay = 20 * time.Second
|
|
|
|
ErrNoRunningContainer = errors.New("no running container")
|
|
)
|
|
|
|
type ServiceOption func(spec *swarm.ServiceSpec)
|
|
|
|
func WithMSNetwork() ServiceOption {
|
|
return WithNetwork(NetworkName)
|
|
}
|
|
|
|
func WithNetwork(name string) ServiceOption {
|
|
return func(spec *swarm.ServiceSpec) {
|
|
spec.Networks = append(spec.Networks,
|
|
swarm.NetworkAttachmentConfig{
|
|
Target: name,
|
|
Aliases: []string{name},
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func WithHostEndpoint(port uint32) ServiceOption {
|
|
return func(spec *swarm.ServiceSpec) {
|
|
spec.EndpointSpec = &swarm.EndpointSpec{
|
|
Mode: "vip",
|
|
Ports: []swarm.PortConfig{
|
|
{
|
|
Protocol: "tcp",
|
|
TargetPort: port,
|
|
PublishedPort: port,
|
|
PublishMode: "host",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithRestartPolicy() ServiceOption {
|
|
return func(spec *swarm.ServiceSpec) {
|
|
spec.TaskTemplate.RestartPolicy = &swarm.RestartPolicy{
|
|
Condition: swarm.RestartPolicyConditionOnFailure,
|
|
MaxAttempts: &RetryServiceAttempts,
|
|
Delay: &RetryServiceDelay,
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithPostgres(name string) ServiceOption {
|
|
return func(spec *swarm.ServiceSpec) {
|
|
if spec.TaskTemplate.ContainerSpec == nil {
|
|
return
|
|
}
|
|
|
|
spec.TaskTemplate.ContainerSpec.Env = append(
|
|
spec.TaskTemplate.ContainerSpec.Env,
|
|
"DB_TYPE=postgres",
|
|
fmt.Sprintf("POSTGRES_HOSTNAME=pg-%s", name),
|
|
fmt.Sprintf("POSTGRES_PORT=%d", PostgresServicePort),
|
|
fmt.Sprintf("POSTGRES_DB=%s", name),
|
|
"POSTGRES_USER=test",
|
|
"POSTGRES_PASSWORD=test",
|
|
)
|
|
}
|
|
}
|
|
|
|
func WithRabbitMQ() ServiceOption {
|
|
return func(spec *swarm.ServiceSpec) {
|
|
if spec.TaskTemplate.ContainerSpec == nil {
|
|
return
|
|
}
|
|
|
|
spec.TaskTemplate.ContainerSpec.Env = append(
|
|
spec.TaskTemplate.ContainerSpec.Env,
|
|
fmt.Sprintf("RABBITMQ_ENDPOINT=amqp://%s:%d", RabbitMQServiceName, RabbitMQServicePort),
|
|
"RABBITMQ_USERNAME=intercloud",
|
|
"RABBITMQ_PASSWORD=intercloud",
|
|
)
|
|
}
|
|
}
|
|
|
|
type Servicer interface {
|
|
Deploy(ctx context.Context, cli *client.Client) error
|
|
}
|
|
|
|
type Service struct {
|
|
spec swarm.ServiceSpec
|
|
name string
|
|
}
|
|
|
|
func (p *Service) GetBaseServiceSpec(serviceName, hostname, imageName, port string, command []string) swarm.ServiceSpec {
|
|
spec := swarm.ServiceSpec{
|
|
Annotations: swarm.Annotations{
|
|
Name: serviceName,
|
|
},
|
|
TaskTemplate: swarm.TaskSpec{
|
|
ContainerSpec: &swarm.ContainerSpec{
|
|
Hostname: hostname,
|
|
Image: imageName,
|
|
Env: []string{
|
|
fmt.Sprintf("PORT=%s", port),
|
|
},
|
|
Command: command,
|
|
},
|
|
},
|
|
Mode: swarm.ServiceMode{
|
|
Replicated: &swarm.ReplicatedService{
|
|
Replicas: &SwarmServiceReplicas,
|
|
},
|
|
},
|
|
}
|
|
|
|
return spec
|
|
}
|
|
|
|
func Deploy(ctx context.Context, cli *client.Client, spec *swarm.ServiceSpec, dependencies []Servicer) error {
|
|
err := utils.CheckServiceHealth(ctx, cli, spec.Annotations.Name)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
if !errors.Is(err, utils.ErrServiceNotFound) {
|
|
return err
|
|
}
|
|
|
|
for _, deps := range dependencies {
|
|
if err := deps.Deploy(ctx, cli); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := utils.CreateService(ctx, cli, spec); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|