func createContainer()

in gce-containers-startup/runtime/runtime.go [226:334]


func createContainer(runner ContainerRunner, auth string, spec api.ContainerSpecStruct) (string, error) {
	if len(spec.Containers) != 1 {
		return "", fmt.Errorf("Exactly one container in declaration expected.")
	}

	container := spec.Containers[0]
	generatedContainerName := fmt.Sprintf("%s-%s-%s", CONTAINER_NAME_PREFIX, container.Name, generateRandomSuffix(4, runner.RandEnv))
	log.Printf("Configured container '%s' will be started with name '%s'.\n", container.Name, generatedContainerName)

	if err := pullImage(runner.Client, auth, container); err != nil {
		return "", err
	}

	if err := deleteOldContainers(runner.Client, container.Name); err != nil {
		return "", err
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	printWarningIfLikelyHasMistake(container.Command, container.Args)

	var runCommand dockerstrslice.StrSlice
	if container.Command != nil {
		runCommand = dockerstrslice.StrSlice(container.Command)
	}
	var runArgs dockerstrslice.StrSlice
	if container.Args != nil {
		runArgs = dockerstrslice.StrSlice(container.Args)
	}

	if err := runner.VolumesEnv.UnmountExistingVolumes(); err != nil {
		log.Printf("Error: failed to unmount volumes:\n%v", err)
	}
	containerVolumeBindingConfigurationMap, volumePrepareError := runner.VolumesEnv.PrepareVolumesAndGetBindings(spec)
	if volumePrepareError != nil {
		return "", volumePrepareError
	}
	volumeBindingConfiguration, volumeBindingFound := containerVolumeBindingConfigurationMap[container.Name]
	if !volumeBindingFound {
		return "", fmt.Errorf("Volume binding configuration for container %s not found in the map. This should not happen.", container.Name)
	}
	// Docker-API compatible types.
	hostPathBinds := []string{}
	for _, hostPathBindConfiguration := range volumeBindingConfiguration {
		hostPathBind := fmt.Sprintf("%s:%s", hostPathBindConfiguration.HostPath, hostPathBindConfiguration.ContainerPath)
		if hostPathBindConfiguration.ReadOnly {
			hostPathBind = fmt.Sprintf("%s:ro", hostPathBind)
		}
		hostPathBinds = append(hostPathBinds, hostPathBind)
	}

	env := []string{}
	for _, envVar := range container.Env {
		env = append(env, fmt.Sprintf("%s=%s", envVar.Name, envVar.Value))
	}

	restartPolicyName := "always"
	if spec.RestartPolicy == nil || *spec.RestartPolicy == api.RestartPolicyAlways {
		restartPolicyName = "always"
	} else if *spec.RestartPolicy == api.RestartPolicyOnFailure {
		restartPolicyName = "on-failure"
	} else if *spec.RestartPolicy == api.RestartPolicyNever {
		restartPolicyName = "no"
	} else {
		return "", fmt.Errorf(
			"Invalid container declaration: Unsupported container restart policy '%s'", *spec.RestartPolicy)
	}

	opts := dockertypes.ContainerCreateConfig{
		Name: generatedContainerName,
		Config: &dockercontainer.Config{
			Entrypoint: runCommand,
			Cmd:        runArgs,
			Image:      container.Image,
			Env:        env,
			OpenStdin:  container.StdIn,
			Tty:        container.Tty,
		},
		HostConfig: &dockercontainer.HostConfig{
			Binds:       hostPathBinds,
			AutoRemove:  false,
			NetworkMode: "host",
			Privileged:  container.SecurityContext.Privileged,
			LogConfig: dockercontainer.LogConfig{
				Type: "json-file",
				Config: map[string]string{
					"max-size": "500m",
					"max-file": "3",
				},
			},
			RestartPolicy: dockercontainer.RestartPolicy{
				Name: restartPolicyName,
			},
		},
	}

	createResp, err := runner.Client.ContainerCreate(
		ctx, opts.Config, opts.HostConfig, opts.NetworkingConfig, opts.Name)
	if ctxErr := contextError(ctx, "Create container"); ctxErr != nil {
		return "", ctxErr
	}
	if err != nil {
		return "", err
	}
	log.Printf("Created a container with name '%s' and ID: %s", generatedContainerName, createResp.ID)

	return createResp.ID, nil
}