func saveImage(imageID, filename string) error { file, err := os.Create(filename) if err != nil { glog.Errorf("Could not create file %s: %s", filename, err) return err } defer func() { if err := file.Close(); err != nil { glog.Warningf("Could not close file %s: %s", filename, err) } }() cd := &docker.ContainerDefinition{ dockerclient.CreateContainerOptions{ Config: &dockerclient.Config{ Cmd: []string{"echo"}, Image: imageID, }, }, dockerclient.HostConfig{}, } ctr, err := docker.NewContainer(cd, false, 10*time.Second, nil, nil) if err != nil { glog.Errorf("Could not create container from image %s. Have you synced lately? (serviced docker sync): %s", imageID, err) return err } glog.V(1).Infof("Created container %s based on image %s", ctr.ID, imageID) defer func() { if err := ctr.Delete(true); err != nil { glog.Errorf("Could not remove container %s (%s): %s", ctr.ID, imageID, err) } }() if err := ctr.Export(file); err != nil { glog.Errorf("Could not export container %s (%s): %v", ctr.ID, imageID, err) return err } glog.Infof("Exported container %s (based on image %s) to %s", ctr.ID, imageID, filename) return nil }
func (svc *IService) create() (*docker.Container, error) { var config dockerclient.Config cd := &docker.ContainerDefinition{ dockerclient.CreateContainerOptions{Name: svc.name(), Config: &config}, dockerclient.HostConfig{}, } config.Image = commons.JoinRepoTag(svc.Repo, svc.Tag) config.Cmd = []string{"/bin/sh", "-c", svc.Command()} // NOTE: USE WITH CARE! // Enabling host networking for an isvc may expose ports // of the isvcs to access outside of the serviced host, potentially // compromising security. if svc.HostNetwork { cd.NetworkMode = "host" glog.Warningf("Host networking enabled for isvc %s", svc.Name) } // attach all exported ports if svc.PortBindings != nil && len(svc.PortBindings) > 0 { config.ExposedPorts = make(map[dockerclient.Port]struct{}) cd.PortBindings = make(map[dockerclient.Port][]dockerclient.PortBinding) for _, binding := range svc.PortBindings { port := dockerclient.Port(fmt.Sprintf("%d", binding.HostPort)) config.ExposedPorts[port] = struct{}{} portBinding := dockerclient.PortBinding{ HostIp: getHostIp(binding), HostPort: port.Port(), } cd.PortBindings[port] = append(cd.PortBindings[port], portBinding) } } glog.V(1).Infof("Bindings for %s = %v", svc.Name, cd.PortBindings) // copy any links to other isvcs if svc.Links != nil && len(svc.Links) > 0 { // To use a link, the source container must be instantiated already, so // the service using a link can't be in the first start group. // // FIXME: Other sanity checks we could add - make sure that the source // container is not in the same group or a later group if svc.StartGroup == 0 { glog.Fatalf("isvc %s can not use docker Links with StartGroup=0", svc.Name) } cd.Links = make([]string, len(svc.Links)) copy(cd.Links, svc.Links) glog.V(1).Infof("Links for %s = %v", svc.Name, cd.Links) } // attach all exported volumes config.Volumes = make(map[string]struct{}) cd.Binds = []string{} // service-specific volumes if svc.Volumes != nil && len(svc.Volumes) > 0 { for src, dest := range svc.Volumes { hostpath := svc.getResourcePath(src) if exists, _ := isDir(hostpath); !exists { if err := os.MkdirAll(hostpath, 0777); err != nil { glog.Errorf("could not create %s on host: %s", hostpath, err) return nil, err } } cd.Binds = append(cd.Binds, fmt.Sprintf("%s:%s", hostpath, dest)) config.Volumes[dest] = struct{}{} } } // global volumes if isvcsVolumes != nil && len(isvcsVolumes) > 0 { for src, dest := range isvcsVolumes { if exists, _ := isDir(src); !exists { glog.Warningf("Could not mount source %s: path does not exist", src) continue } cd.Binds = append(cd.Binds, fmt.Sprintf("%s:%s", src, dest)) config.Volumes[dest] = struct{}{} } } // attach environment variables for key, val := range envPerService[svc.Name] { config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, val)) } return docker.NewContainer(cd, false, 5*time.Second, nil, nil) }
// StartService starts a new instance of the specified service and updates the control center state accordingly. func (a *HostAgent) StartService(svc *service.Service, state *servicestate.ServiceState, exited func(string)) error { glog.V(2).Infof("About to start service %s with name %s", svc.ID, svc.Name) client, err := NewControlClient(a.master) if err != nil { glog.Errorf("Could not start ControlPlane client %v", err) return err } defer client.Close() // start from a known good state if state.DockerID != "" { if ctr, err := docker.FindContainer(state.DockerID); err != nil { glog.Errorf("Could not find container %s for %s", state.DockerID, state.ID) } else if err := ctr.Delete(true); err != nil { glog.Errorf("Could not delete container %s for %s", state.DockerID, state.ID) } } // create the docker client Config and HostConfig structures necessary to create and start the service config, hostconfig, err := configureContainer(a, client, svc, state, a.virtualAddressSubnet) if err != nil { glog.Errorf("can't configure container: %v", err) return err } cjson, _ := json.MarshalIndent(config, "", " ") glog.V(3).Infof(">>> CreateContainerOptions:\n%s", string(cjson)) hcjson, _ := json.MarshalIndent(hostconfig, "", " ") glog.V(3).Infof(">>> HostConfigOptions:\n%s", string(hcjson)) cd := &docker.ContainerDefinition{ dockerclient.CreateContainerOptions{Name: state.ID, Config: config}, *hostconfig, } ctr, err := docker.NewContainer(cd, false, 10*time.Second, nil, nil) if err != nil { glog.Errorf("Error trying to create container %v: %v", config, err) return err } var started sync.WaitGroup started.Add(1) ctr.OnEvent(docker.Start, func(cid string) { glog.Infof("Instance %s (%s) for %s (%s) has started", state.ID, ctr.ID, svc.Name, svc.ID) started.Done() }) ctr.OnEvent(docker.Die, func(cid string) { defer exited(state.ID) glog.Infof("Instance %s (%s) for %s (%s) has died", state.ID, ctr.ID, svc.Name, svc.ID) state.DockerID = cid a.removeInstance(state.ID, ctr) }) if err := ctr.Start(time.Hour); err != nil { glog.Errorf("Could not start service state %s (%s) for service %s (%s): %s", state.ID, ctr.ID, svc.Name, svc.ID, err) a.removeInstance(state.ID, ctr) return err } started.Wait() if err := updateInstance(state, ctr); err != nil { glog.Errorf("Could not update instance %s (%s) for service %s (%s): %s", state.ID, ctr.ID, svc.Name, svc.ID, err) ctr.Stop(45 * time.Second) return err } go a.setProxy(svc, ctr) return nil }