容器是特殊的進程露泊,runc則是他們的直接管理工具斗塘,contanerd則是提供對runc的管理。contanerd通過shim(墊片代理)屏蔽底層runtime實現(xiàn)(如runc),管理本機所有的runc和他的容器進程實例。一個容器進程實例對應(yīng)一個task载弄。
contanerd 可以完成鏡像下載unpack到容器啟動的整個過程,并管理容器的整個生命周期撵颊。容器的元數(shù)據(jù)實際會存儲在boltdb(golang版本地kv db)中宇攻。contanerd完成容器的信息存儲和狀態(tài)存儲,是容器的虛擬世界管理映射倡勇。
Container為容器的數(shù)據(jù)結(jié)構(gòu)標識逞刷,可被存儲在boltdb中,task是執(zhí)行容器的運行時對象妻熊,相當于類和對象的關(guān)系夸浅。task實際會調(diào)用綁定的runtime,Containerd默認采用runc作為runtime固耘,其他容器運行時如(runtime)也可以通過對接shim接口來接入Containerd题篷。
runc相當于一個命令行工具通過命令將container啟動起來就不管了词身,containerd則是一個守護進程厅目。
shim service負責直接和container接觸,代理其IO并接收退出信號,提供統(tǒng)一運行接口(啟動 刪除 運行)损敷,在shim service 之上會有一個統(tǒng)一管理進程來對各個shim或者說各個task實例進行管理葫笼。
Shims實現(xiàn)了對bundle目錄的rootfs系統(tǒng)的掛載,卸載拗馒,containerd的文件系統(tǒng)是由snapshoter管理的路星,containerd 為不同文件系統(tǒng)提供管理如ext4 overlay, 每種不同的文件系統(tǒng)對應(yīng)各自的實現(xiàn)的Snapshotter, 用戶可以在配置文件中指定Snapshotter诱桂。
containerd 中的service 都是通過plugin加grpc方式組織管理洋丐,實際就是將service封裝成plugin形式,然后調(diào)用統(tǒng)一接口啟動封裝成plugin的所有服務(wù)挥等。
// shim 啟動入口 v2 "github.com/containerd/containerd/runtime/v2/runc/v2"
// v2 是一個實際的runc runtime shim service 管理runc的生命周期友绝,提供實際的api 如創(chuàng)建 container 在容器中啟動進程等
func main() {
shim.Run("io.containerd.runc.v2", v2.New)
}
// containerd/runtime/v2/shim/shim.go
// 初始化并啟動shim server
func Run(id string, initFunc Init, opts ...BinaryOpts) {
run(id, initFunc, config)
}
type Init func(context.Context, string, Publisher, func()) (Shim, error)
func run(id string, initFunc Init, config Config) error {
service, err := initFunc(ctx, idFlag, publisher, cancel)
}
// containerd/client.go Client為客戶調(diào)用containerd接口,為taskService肝劲,
// diffService等提供一個統(tǒng)一的接口迁客,通過grpc方式來調(diào)用。
type Client struct {
services
connMu sync.Mutex
conn *grpc.ClientConn
runtime string
defaultns string
platform platforms.MatchComparer
connector func() (*grpc.ClientConn, error)
}
// 創(chuàng)建client
client, err := containerd.New("/run/containerd/containerd.sock")
// 實際通過unix socket來連接后端的grpc服務(wù)
func DialAddress(address string) string {
return fmt.Sprintf("unix://%s", address)
}
// 通過init.go initial進程調(diào)用runc創(chuàng)建容器(調(diào)用runc cmd來實現(xiàn))
func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTaskRequest) (_ *Container, retErr error) {
p, err := newInit(
ctx,
r.Bundle,
filepath.Join(r.Bundle, "work"),
ns,
platform,
config,
&opts,
rootfs,
)
p.Create(ctx, config)
}
func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
// runtime為*runc.Runc辞槐, 實際是調(diào)用runc命令創(chuàng)建container
p.runtime.Create(ctx, r.ID, r.Bundle, opts)
}