Esempio n. 1
0
func AppDeploy(configStore *config.Store, serviceRuntime *runtime.ServiceRuntime, app, env, version string) error {
	log.Printf("Pulling image %s...", version)

	image, err := serviceRuntime.PullImage(version, "")
	if image == nil || err != nil {
		return fmt.Errorf("unable to pull %s. Has it been released yet?", version)
	}

	svcCfg, err := configStore.GetApp(app, env)
	if err != nil {
		return fmt.Errorf("unable to deploy app: %s.", err)
	}

	if svcCfg == nil {
		return fmt.Errorf("app %s does not exist. Create it first.", app)
	}

	svcCfg.SetVersion(version)
	svcCfg.SetVersionID(utils.StripSHA(image.ID))

	updated, err := configStore.UpdateApp(svcCfg, env)
	if err != nil {
		return fmt.Errorf("could not store version: %s", err)
	}
	if !updated {
		return fmt.Errorf("%s NOT deployed.", version)
	}
	log.Printf("Deployed %s.\n", version)
	return nil
}
Esempio n. 2
0
// inspectImage checks that the running image matches the config.
// We only use this to print warnings, since we likely need to deploy a new
// config version to fix the inconsistency.
func inspectImage(appCfg config.App) {
	image, err := serviceRuntime.InspectImage(appCfg.Version())
	if err != nil {
		log.Println("error inspecting image", appCfg.Version())
		return
	}

	if utils.StripSHA(image.ID) != appCfg.VersionID() {
		log.Printf("warning: %s image ID does not match config", appCfg.Name())
	}
}
Esempio n. 3
0
// Pull a docker image.
// If we have an image matching the tag, and the given id matches the current
// image, don't fetch a new one from the registry.
func (s *ServiceRuntime) PullImage(version, id string) (*docker.Image, error) {
	image, err := s.InspectImage(version)

	if err != nil && err != docker.ErrNoSuchImage {
		return nil, err
	}

	if image != nil && utils.StripSHA(image.ID) == id {
		return image, nil
	}

	registry, repository, tag := utils.SplitDockerImage(version)

	// pull it down locally
	pullOpts := docker.PullImageOptions{
		Repository:   repository,
		Tag:          tag,
		OutputStream: log.DefaultLogger}

	dockerAuth := findAuth(registry)

	if registry != "" {
		pullOpts.Repository = registry + "/" + repository
	} else {
		pullOpts.Repository = repository
	}
	pullOpts.Registry = registry
	pullOpts.Tag = tag

	retries := 0
	for {
		retries += 1
		err = s.dockerClient.PullImage(pullOpts, dockerAuth)
		if err != nil {

			if retries > 3 {
				return image, err
			}
			log.Errorf("ERROR: error pulling image %s. Attempt %d: %s", version, retries, err)
			continue
		}
		break
	}

	return s.InspectImage(version)
}
Esempio n. 4
0
func (s *ServiceRuntime) Start(env, pool string, appCfg config.App) (*docker.Container, error) {

	img := appCfg.Version()

	image, err := s.PullImage(img, appCfg.VersionID())
	if err != nil {
		return nil, err
	}

	if utils.StripSHA(image.ID) != appCfg.VersionID() {
		log.Warnf("warning: ID for image %s doesn't match configuration", img)
	}

	// setup env vars from etcd
	var envVars []string
	envVars = append(envVars, "ENV"+"="+env)

	for key, value := range appCfg.Env() {
		if key == "ENV" {
			continue
		}
		envVars = append(envVars, strings.ToUpper(key)+"="+s.replaceVarEnv(value, s.hostIP))
	}

	instanceId, err := s.NextInstanceSlot(appCfg.Name(), strconv.FormatInt(appCfg.ID(), 10))
	if err != nil {
		return nil, err
	}

	envVars = append(envVars, fmt.Sprintf("HOST_IP=%s", s.hostIP))
	envVars = append(envVars, fmt.Sprintf("GALAXY_APP=%s", appCfg.Name()))
	envVars = append(envVars, fmt.Sprintf("GALAXY_VERSION=%s", strconv.FormatInt(appCfg.ID(), 10)))
	envVars = append(envVars, fmt.Sprintf("GALAXY_INSTANCE=%s", strconv.FormatInt(int64(instanceId), 10)))

	publicDns, err := EC2PublicHostname()
	if err != nil {
		log.Warnf("Unable to determine public hostname. Not on AWS? %s", err)
		publicDns = "127.0.0.1"
	}
	envVars = append(envVars, fmt.Sprintf("PUBLIC_HOSTNAME=%s", publicDns))

	containerName := appCfg.ContainerName() + "." + strconv.FormatInt(int64(instanceId), 10)
	container, err := s.dockerClient.InspectContainer(containerName)
	_, ok := err.(*docker.NoSuchContainer)
	if err != nil && !ok {
		return nil, err
	}

	// Existing container is running or stopped.  If the image has changed, stop
	// and re-create it.
	if container != nil && container.Image != image.ID {
		if container.State.Running || container.State.Restarting || container.State.Paused {
			log.Printf("Stopping %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])
			err := s.dockerClient.StopContainer(container.ID, 10)
			if err != nil {
				return nil, err
			}
		}

		log.Printf("Removing %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])
		err = s.dockerClient.RemoveContainer(docker.RemoveContainerOptions{
			ID: container.ID,
		})
		if err != nil {
			return nil, err
		}
		container = nil
	}

	if container == nil {

		config := &docker.Config{
			Image: img,
			Env:   envVars,
		}

		mem := appCfg.GetMemory(pool)
		if mem != "" {
			m, err := utils.ParseMemory(mem)
			if err != nil {
				return nil, err
			}
			config.Memory = m
		}

		cpu := appCfg.GetCPUShares(pool)
		if cpu != "" {
			if c, err := strconv.Atoi(cpu); err == nil {
				config.CPUShares = int64(c)
			}
		}

		log.Printf("Creating %s version %s", appCfg.Name(), appCfg.Version())
		container, err = s.dockerClient.CreateContainer(docker.CreateContainerOptions{
			Name:   containerName,
			Config: config,
		})
		if err != nil {
			return nil, err
		}
	}

	log.Printf("Starting %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])

	config := &docker.HostConfig{
		PublishAllPorts: true,
		RestartPolicy: docker.RestartPolicy{
			Name:              "on-failure",
			MaximumRetryCount: 16,
		},
		LogConfig: docker.LogConfig{
			Type:   "syslog",
			Config: map[string]string{"syslog-tag": containerName},
		},
	}

	if s.dns != "" {
		config.DNS = []string{s.dns}
	}
	err = s.dockerClient.StartContainer(container.ID, config)

	return container, err
}