命令:
ctr containers -h
NAME:
ctr containers - manage containers (metadata)
USAGE:
ctr containers command [command options] [arguments...]
COMMANDS:
list, ls list all tasks or those that match a filter
delete, del, rm delete an existing container
label Set and clear labels for a container.
OPTIONS:
--help, -h show help
一. ctr containers list 命令
1.1 服务端收到 GRPC 请求
func _Containers_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListContainersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ContainersServer).List(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/containerd.services.containers.v1.Containers/List",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ContainersServer).List(ctx, req.(*ListContainersRequest))
}
return interceptor(ctx, in, info, handler)
}
1.2 services/containers/service.go 中 重要的函数 store.List 为实现的接口
func (s *Service) List(ctx context.Context, req *api.ListContainersRequest) (*api.ListContainersResponse, error) {
var resp api.ListContainersResponse
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
containers, err := store.List(ctx, req.Filters...)
if err != nil {
return err
}
resp.Containers = containersToProto(containers)
return nil
}))
}
1.3 根据 withStore 函数可以得到 store 为 metadata.NewContainerStore,路径 /metadata/containers.go 中,containerStore 结构体是包裹的是操作数据库
type containerStore struct {
tx *bolt.Tx
}
func NewContainerStore(tx *bolt.Tx) containers.Store {
return &containerStore{
tx: tx,
}
}
1.4 List 函数中 getContainerBucket 如果为空,证明没有container 在 1.4.1 中讲解,readContainer 将数据读入到 container 中。
func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.Container, error) {
namespace, err := namespaces.NamespaceRequired(ctx)
filter, err := filters.ParseAll(fs...)
bkt := getContainersBucket(s.tx, namespace)
if bkt == nil {
return nil, nil
}
var m []containers.Container
if err := bkt.ForEach(func(k, v []byte) error {
cbkt := bkt.Bucket(k)
if cbkt == nil {
return nil
}
container := containers.Container{ID: string(k)}
if err := readContainer(&container, cbkt); err != nil {
return errors.Wrap(err, "failed to read container")
}
if filter.Match(adaptContainer(container)) {
m = append(m, container)
}
return nil
}); err != nil {
return nil, err
}
return m, nil
}
1.4.1 getContainersBucket 中 namespace 一般默认为 default,bucketKeyObjectContainers 为 contaiers,1.4.1.1 分析 bolt.Tx 结构体,数据库的有点乱,现在只知道是操作数据库就行了。尴尬!!!tx.Bucket 在 1.4.1.2 讲解
func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
}
func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
bkt := tx.Bucket(keys[0])
for _, key := range keys[1:] {
if bkt == nil {
break
}
bkt = bkt.Bucket(key)
}
return bkt
}
1.4.1.1 结构体
type Tx struct {
writable bool
managed bool
db *DB
meta *meta
root Bucket
pages map[pgid]*page
stats TxStats
commitHandlers []func()
WriteFlag int
Bucket 表示 key / value 对存在数据库中
// Bucket represents a collection of key/value pairs inside the database.
type Bucket struct {
*bucket
tx *Tx // the associated transaction
buckets map[string]*Bucket // subbucket cache
page *page // inline page reference
rootNode *node // materialized node for the root page.
nodes map[pgid]*node // node cache
// Sets the threshold for filling nodes when they split. By default,
// the bucket will fill to 50% but it can be useful to increase this
// amount if you know that your write workloads are mostly append-only.
//
// This is non-persisted across transactions so it must be set in every Tx.
FillPercent float64
}
1.4.1.2 Bucket 函数根据名字检索,返回 Bucket 结构体
func (tx *Tx) Bucket(name []byte) *Bucket {
return tx.root.Bucket(name)
}