"docker查看容器过程分析"

  "docker容器ps"

Posted by Xu on July 23, 2017

Docker ps查看容器信息流程分析

同样,client到服务器端发送数据的部分不作分析,直接从服务器端路由的ps命令实现方法getContainersJSON来切入:

dockerps

func (s *containerRouter) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}
	filter, err := filters.FromParam(r.Form.Get("filters"))
	if err != nil {
		return err
	}

	config := &types.ContainerListOptions{
		All:     httputils.BoolValue(r, "all"),
		Size:    httputils.BoolValue(r, "size"),
		Since:   r.Form.Get("since"),
		Before:  r.Form.Get("before"),
		Filters: filter,
	}//同样首先解析请求得到配置信息

	if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
		limit, err := strconv.Atoi(tmpLimit)
		if err != nil {
			return err
		}
		config.Limit = limit
	}

	containers, err := s.backend.Containers(config)//根据配置信息获取容器信息
	if err != nil {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, containers)
}

Containers经过一层包装调用reduceContainers:

// reduceContainers parses the user's filtering options and generates the list of containers to return based on a reducer.
func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reducer containerReducer) ([]*types.Container, error) {
	var (
		containers = []*types.Container{}//首先定义一个空的容器对象框架
	)

	ctx, err := daemon.foldFilter(config)//根据容器配置的过滤条件生成对应的过滤器ctx
	if err != nil {
		return nil, err
	}

	// fastpath to only look at a subset of containers if specific name
	// or ID matches were provided by the user--otherwise we potentially
	// end up locking and querying many more containers than intended
	containerList := daemon.filterByNameIDMatches(ctx)//根据名称或容器直接从daemon.containers对象中获取对应容器信息,如果ps命令没有提供name和id则调用daemon.List()获取所有的容器信息

	for _, container := range containerList {
		t, err := daemon.reducePsContainer(container, ctx, reducer)//遍历所有容器对象根据过滤器信息得到对应容器
		if err != nil {
			if err != errStopIteration {
				return nil, err
			}
			break
		}
		if t != nil {
			containers = append(containers, t)
			ctx.idx++
		}
	}//遍历得到的容器信息添加到返回对象containers中去

	return containers, nil
}

接下来介绍daemon.List()的实现

func (c *memoryStore) List() []*Container {
	containers := History(c.all())//得到memoryStore的所有容器对象,这里的memoryStore其实就是daemon.containers对象
	containers.sort()
	return containers
}

根据过滤器信息得到容器对象

func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
	container.Lock()

	// filter containers to return
	action := includeContainerInList(container, ctx)//与ctx过滤器中的所有过滤信息进行匹配,得到该容器是否被包含或被排除的信息
	switch action {
	case excludeContainer://不满足过滤器信息,被排除
		container.Unlock()
		return nil, nil
	case stopIteration:
		container.Unlock()
		return nil, errStopIteration
	}

	// transform internal container struct into api structs
	//执行到这一步说明,过滤器匹配成功,调用reducer即transformContainer将容器对象转换API接受的结构,也就是将container.Container转化成types.Container结构newC
	newC, err := reducer(container, ctx)
	container.Unlock()
	if err != nil {
		return nil, err
	}

	// release lock because size calculation is slow
	if ctx.Size {
		sizeRw, sizeRootFs := daemon.getSize(newC.ID)//获取容器的真实大小和虚拟大小
		newC.SizeRw = sizeRw
		newC.SizeRootFs = sizeRootFs
	}
	return newC, nil//返回types.Container对象
}