Beispiel #1
0
// Returns the type of load balancer that should be used (ELB/ALB).
func loadBalancerType(app *scheduler.App, process *scheduler.Process) string {
	check := []string{
		"EMPIRE_X_LOAD_BALANCER_TYPE",
		"LOAD_BALANCER_TYPE", // For backwards compatibility.
	}
	env := scheduler.Env(app, process)

	for _, n := range check {
		if v, ok := env[n]; ok {
			return v
		}
	}

	// Default when not set.
	return classicLoadBalancer
}
Beispiel #2
0
// ContainerDefinition generates an ECS ContainerDefinition for a process.
func (t *EmpireTemplate) ContainerDefinition(app *scheduler.App, p *scheduler.Process) *ecs.ContainerDefinition {
	command := []*string{}
	for _, s := range p.Command {
		ss := s
		command = append(command, &ss)
	}

	environment := envByKey{}
	for k, v := range scheduler.Env(app, p) {
		environment = append(environment, &ecs.KeyValuePair{
			Name:  aws.String(k),
			Value: aws.String(v),
		})
	}

	sort.Sort(environment)

	labels := make(map[string]*string)
	for k, v := range scheduler.Labels(app, p) {
		labels[k] = aws.String(v)
	}

	ulimits := []*ecs.Ulimit{}
	if p.Nproc != 0 {
		ulimits = []*ecs.Ulimit{
			&ecs.Ulimit{
				Name:      aws.String("nproc"),
				SoftLimit: aws.Int64(int64(p.Nproc)),
				HardLimit: aws.Int64(int64(p.Nproc)),
			},
		}
	}

	return &ecs.ContainerDefinition{
		Name:             aws.String(p.Type),
		Cpu:              aws.Int64(int64(p.CPUShares)),
		Command:          command,
		Image:            aws.String(p.Image.String()),
		Essential:        aws.Bool(true),
		Memory:           aws.Int64(int64(p.MemoryLimit / bytesize.MB)),
		Environment:      environment,
		LogConfiguration: t.LogConfiguration,
		DockerLabels:     labels,
		Ulimits:          ulimits,
	}
}
Beispiel #3
0
func (s *Scheduler) Run(ctx context.Context, app *scheduler.App, p *scheduler.Process, in io.Reader, out io.Writer) error {
	attached := out != nil || in != nil

	if !attached {
		return errors.New("cannot run detached processes with Docker scheduler")
	}

	labels := scheduler.Labels(app, p)
	labels[runLabel] = Attached

	if err := s.docker.PullImage(ctx, docker.PullImageOptions{
		Registry:     p.Image.Registry,
		Repository:   p.Image.Repository,
		Tag:          p.Image.Tag,
		OutputStream: replaceNL(out),
	}); err != nil {
		return fmt.Errorf("error pulling image: %v", err)
	}

	container, err := s.docker.CreateContainer(ctx, docker.CreateContainerOptions{
		Name: uuid.New(),
		Config: &docker.Config{
			Tty:          true,
			AttachStdin:  true,
			AttachStdout: true,
			AttachStderr: true,
			OpenStdin:    true,
			Memory:       int64(p.MemoryLimit),
			CPUShares:    int64(p.CPUShares),
			Image:        p.Image.String(),
			Cmd:          p.Command,
			Env:          envKeys(scheduler.Env(app, p)),
			Labels:       labels,
		},
		HostConfig: &docker.HostConfig{
			LogConfig: docker.LogConfig{
				Type: "json-file",
			},
		},
	})
	if err != nil {
		return fmt.Errorf("error creating container: %v", err)
	}
	defer s.docker.RemoveContainer(ctx, docker.RemoveContainerOptions{
		ID:            container.ID,
		RemoveVolumes: true,
		Force:         true,
	})

	if err := s.docker.StartContainer(ctx, container.ID, nil); err != nil {
		return fmt.Errorf("error starting container: %v", err)
	}
	defer tryClose(out)

	if err := s.docker.AttachToContainer(ctx, docker.AttachToContainerOptions{
		Container:    container.ID,
		InputStream:  in,
		OutputStream: out,
		ErrorStream:  out,
		Logs:         true,
		Stream:       true,
		Stdin:        true,
		Stdout:       true,
		Stderr:       true,
		RawTerminal:  true,
	}); err != nil {
		return fmt.Errorf("error attaching to container: %v", err)
	}

	return nil
}
Beispiel #4
0
func (m *Scheduler) taskDefinitionInput(app *scheduler.App, p *scheduler.Process, loadBalancer *lb.LoadBalancer) (*ecs.RegisterTaskDefinitionInput, error) {
	// ecs.ContainerDefinition{Command} is expecting a []*string
	var command []*string
	for _, s := range p.Command {
		ss := s
		command = append(command, &ss)
	}

	var environment []*ecs.KeyValuePair
	for k, v := range scheduler.Env(app, p) {
		environment = append(environment, &ecs.KeyValuePair{
			Name:  aws.String(k),
			Value: aws.String(v),
		})
	}

	// If there's a load balancer attached, generate the port mappings and
	// expose the container port to the process via the PORT environment
	// variable.
	var ports []*ecs.PortMapping
	if loadBalancer != nil {
		ports = append(ports, &ecs.PortMapping{
			HostPort:      aws.Int64(loadBalancer.InstancePort),
			ContainerPort: aws.Int64(ContainerPort),
		})
		environment = append(environment, &ecs.KeyValuePair{
			Name:  aws.String("PORT"),
			Value: aws.String(fmt.Sprintf("%d", ContainerPort)),
		})
	}

	labels := make(map[string]*string)
	for k, v := range scheduler.Labels(app, p) {
		labels[k] = aws.String(v)
	}

	var ulimits []*ecs.Ulimit
	if p.Nproc != 0 {
		ulimits = []*ecs.Ulimit{
			&ecs.Ulimit{
				Name:      aws.String("nproc"),
				SoftLimit: aws.Int64(int64(p.Nproc)),
				HardLimit: aws.Int64(int64(p.Nproc)),
			},
		}
	}

	return &ecs.RegisterTaskDefinitionInput{
		Family: aws.String(p.Type),
		ContainerDefinitions: []*ecs.ContainerDefinition{
			&ecs.ContainerDefinition{
				Name:             aws.String(p.Type),
				Cpu:              aws.Int64(int64(p.CPUShares)),
				Command:          command,
				Image:            aws.String(p.Image.String()),
				Essential:        aws.Bool(true),
				Memory:           aws.Int64(int64(p.MemoryLimit / MB)),
				Environment:      environment,
				LogConfiguration: m.logConfiguration,
				PortMappings:     ports,
				DockerLabels:     labels,
				Ulimits:          ulimits,
			},
		},
	}, nil
}