Análise de código-fonte de recuperação de lixo Kubelet (contêineres retirados e imagens não utilizadas)

1. Visão Geral:

1.1 Ambiente de código

As informações da versão são as seguintes:
a. Cluster kubernetes: v1.15.0

1.2 Breve descrição da coleta de lixo

Para reduzir o consumo de recursos do nó, duas corrotinas estão sendo executadas dentro do componente kubelet. Uma corrotina limpa o contêiner encerrado no nó atual a cada 1 minuto (o período de tempo não pode ser modificado e o código está morto). 5 minutos (o período de tempo não pode ser modificado e o código é difícil de escrever) para limpar as imagens não utilizadas no nó atual.


2 Parâmetros que afetam a coleta de lixo:

2.1 Parâmetros que afetam a coleta de lixo que não podem ser configurados pelo usuário

ContainerGCPeriod, fixado em 1 minuto, este valor é uma constante, o método de tarefa cronometrada é usado diretamente ao chamar esta constante.
ImageGCPeriod é fixado em 5 minutos. Este valor é uma constante. O método de tarefa cronometrada usa essa constante diretamente ao chamar.

const (
	// ContainerGCPeriod is the period for performing container garbage collection.
	ContainerGCPeriod = time.Minute
	// ImageGCPeriod is the period for performing image garbage collection.
	ImageGCPeriod = 5 * time.Minute
)

2.2 Parâmetros configuráveis ​​pelo usuário que afetam a coleta de lixo

2.2.1 Três parâmetros relacionados à coleta de lixo do contêiner

(Ele só pode ser escrito no parâmetro de comando de inicialização kubelet, não em seu arquivo de configuração, porque não há campos relacionados no objeto kubeconfigration)

a, --maximum-dead-containers-per-container:
quantos contêineres parados podem ser armazenados em um pod, no máximo, o padrão é 1;
b, --maximum-dead-containers:
quantos contêineres parados podem ser mantidos o nó atual, O padrão é -1, o que significa que não há limite;
c, --minimum-container-ttl-duration:
o tempo mínimo que o contêiner que saiu pode sobreviver, o padrão é 0s;

fs.DurationVar(&f.MinimumGCAge.Duration, "minimum-container-ttl-duration", f.MinimumGCAge.Duration, "Minimum age for a finished container before it is garbage collected.  Examples: '300ms', '10s' or '2h45m'")
fs.Int32Var(&f.MaxPerPodContainerCount, "maximum-dead-containers-per-container", f.MaxPerPodContainerCount, "Maximum number of old instances to retain per container.  Each container takes up some disk space.")
fs.Int32Var(&f.MaxContainerCount, "maximum-dead-containers", f.MaxContainerCount, "Maximum number of old instances of containers to retain globally.  Each container takes up some disk space. To disable, set to a negative number.")

Os valores do parâmetro maximum-dead-containers-per-container, maximum-dead-containers, –minimum-container-ttl-duration serão salvos neste objeto de estrutura, que será tratado como um método de coleta de lixo GarbageCollect () 'S entrada.


type ContainerGCPolicy struct {
	// Minimum age at which a container can be garbage collected, zero for no limit.
	MinAge time.Duration

	// Max number of dead containers any single pod (UID, container name) pair is
	// allowed to have, less than zero for no limit.
	MaxPerPodContainer int

	// Max number of total dead containers, less than zero for no limit.
	MaxContainers int
}

2.2.2 Existem três parâmetros principais relacionados à recuperação do espelho:

–Image-gc-high-threshold: quando o uso do disco atinge este limite, o kubelet começa a recuperar a imagem, o padrão é 85%;
–image-gc-low-threshold: quando o uso do disco atinge este limite, o kubelet para de reivindicar a imagem, o padrão é 80%;
--minimum-image-ttl-duration: o tempo mínimo de retenção de imagens não utilizadas antes de serem recicladas, o padrão é 2m0s;

fs.DurationVar(&c.ImageMinimumGCAge.Duration, "minimum-image-ttl-duration", c.ImageMinimumGCAge.Duration, "Minimum age for an unused image before it is garbage collected.  Examples: '300ms', '10s' or '2h45m'.")
fs.Int32Var(&c.ImageGCHighThresholdPercent, "image-gc-high-threshold", c.ImageGCHighThresholdPercent, "The percent of disk usage after which image garbage collection is always run. Values must be within the range [0, 100], To disable image garbage collection, set to 100. ")
fs.Int32Var(&c.ImageGCLowThresholdPercent, "image-gc-low-threshold", c.ImageGCLowThresholdPercent, "The percent of disk usage before which image garbage collection is never run. Lowest disk usage to garbage collect to. Values must be within the range [0, 100] and should not be larger than that of --image-gc-high-threshold.")

Esses três parâmetros também podem ser gravados em var / lib / kubelet / config.yaml, que são
imageGCHighThresholdPercent
imageGCLowThresholdPercent
ImageMinimumGCAge


3 O processo de contêiner de reciclagem de kubelet:

1) O Kubelet primeiro recupera os contêineres de negócios recicláveis ​​em todos os pods (lista os contêineres recicláveis, a ação de reclamação é chamar o método killContainer e o método removeContainer do objeto kubeGenericRuntimeManager. O valor do objeto ContainerGCPolicy afeta a triagem do contêiner e bifurcações de código)

2) o kubelet recupera os sandboxes recicláveis ​​em todos os pods (lista os contêineres recicláveis, a ação reclaim é chamar o método killContainer e o método removeContainer do objeto kubeGenericRuntimeManager. O valor do objeto ContainerGCPolicy afeta a triagem do contêiner e as bifurcações de código)

3) O Kubelet finalmente recupera os diretórios de log de pods e contêineres (diretório / var / log / pods / e / var / log / containers / diretório).

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui


4 O processo de recuperação da imagem por kubelet:

Obtenha as informações do disco (capacidade, uso, etc.) da partição do disco onde o espelho está localizado e determine se o uso do disco é maior do que o limite configurado pelo usuário (o valor de --image-gc-high-threshold ). Se for uma tentativa de excluir espelhos não usados, deixe o uso de discos de espelho cair abaixo do limite. Para ser mais direto, o kubelet executa o comando df para consultar a taxa de uso do disco. Se a taxa de uso for maior que o limite definido pelo usuário no parâmetro de comando ou arquivo de configuração, o comando docker rmi é executado para excluir as imagens não utilizadas.

5 estruturas importantes

type Kubelet struct {
	
	/*
		其他属性
	*/
	
	// Policy for handling garbage collection of dead containers.
	//用于回收退出状态的容器
	//实现类是结构体realContainerGC,包含了kubeGenericRuntimeManager对象,位于k8s.io/kubernetes/pkg/kubelet/container/container_gc.go
	containerGC kubecontainer.ContainerGC

	// Manager for image garbage collection.
	//用于回收未使用的镜像
	//实现类是结构体realImageGCManager,位于k8s.io/kubernetes/pkg/kubelet/images/image_gc_manager.go
	imageManager images.ImageGCManager
}

type kubeGenericRuntimeManager struct {

	/*
		其他属性
	*/

	// Container GC manager
	containerGC *containerGC
	
	// gRPC service clients
	// 以下两个属性包含了grpc客户端,最终是调用容器运行时(一般情况为docker)的容器接口和镜像接口
	runtimeService internalapi.RuntimeService
	imageService   internalapi.ImageManagerService
}

6 código de backbone



//在创建kubelet对象时(即kubelet还没运行主循环),就启动了垃圾回收的协程StartGarbageCollection()
func createAndInitKubelet(...) {
    k, err = kubelet.NewMainKubelet(
       //代码省略
    )
    if err != nil {
        return nil, err
    }
    //代码省略
    
    k.StartGarbageCollection()
    return k, nil
}


func (kl *Kubelet) StartGarbageCollection() {
    loggedContainerGCFailure := false

    // 1)启动容器垃圾回收服务
	//启动协程定时执行kl.containerGC.GarbageCollect()方法,此方法是被封装在wait.Until()方法中,从而起到定时执行的效果。
	go wait.Until(func() {
		if err := kl.containerGC.GarbageCollect(); err != nil {
			//此代码可忽略
		} else {
			//此代码可忽略
			klog.V(vLevel).Infof("Container garbage collection succeeded")
		}
	}, ContainerGCPeriod, wait.NeverStop)
	
    //2)当ImageGCHighThresholdPercent 参数的值为100时,直接返回,即不启动镜像回收的协程。
    if kl.kubeletConfiguration.ImageGCHighThresholdPercent == 100 {
        return
    }

    //3)启动镜像垃圾回收服务
    //启动协程定时执行kl.imageManager.GarbageCollect()方法,此方法是被封装在wait.Until()方法中,从而起到定时执行的效果。
	go wait.Until(func() {
		if err := kl.imageManager.GarbageCollect(); err != nil {
			//此代码可忽略
		} else {
			//此代码可忽略
			klog.V(vLevel).Infof("Image garbage collection succeeded")
		}
	}, ImageGCPeriod, wait.NeverStop)
}



func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy, allSourcesReady bool, evictTerminatedPods bool) error {
    errors := []error{}
    // 回收pod 中的container
    //kubeGenericRuntimeManager对象的killContainer方法和removeContainer方法
    if err := cgc.evictContainers(gcPolicy, allSourcesReady, evictTerminatedPods); err != nil {
        errors = append(errors, err)
    }

    // 回收pod中的sandboxes
     //kubeGenericRuntimeManager对象的killContainer方法和removeContainer方法
    if err := cgc.evictSandboxes(evictTerminatedPods); err != nil {
        errors = append(errors, err)
    }

    //回收pod和容器的日志目录(/var/log/pods/目录和/var/log/containers/目录)
    if err := cgc.evictPodLogsDirectories(allSourcesReady); err != nil {
        errors = append(errors, err)
    }
    return utilerrors.NewAggregate(errors)
}


func (im *realImageGCManager) GarbageCollect() error {
    // 获取容器镜像存储目录所在分区的磁盘信息
    fsStats, err := im.statsProvider.ImageFsStats()
    
	/*
	一些异常情况判断和处理
	*/
	
    //若分区使用率使用率大于HighThresholdPercent,此时进入if语句进行回收未使用的镜像
    usagePercent := 100 - int(available*100/capacity)
    if usagePercent >= im.policy.HighThresholdPercent {
        //计算需要释放的磁盘量,相比用户设置的阈值
        amountToFree := capacity*int64(100-im.policy.LowThresholdPercent)/100 - available

        //调用im.freeSpace()方法真正地回收未使用的镜像,底层是调用kubeGenericRuntimeManager对象的RemoveImage()方法
        freed, err := im.freeSpace(amountToFree, time.Now())
        if err != nil {
            return err
        }
		
		/*
			一些日志相关的代码
			此处省略
		*/       
    }

    return nil
}

7 Resumo

kubelet abre uma tarefa de cronometragem para excluir os contêineres e as imagens não utilizadas que são encerradas no pod. Alguns parâmetros do comando e do arquivo de configuração podem afetar a execução dessas duas tarefas de cronometragem, e o usuário executa os comandos docker rmi e docker rm no linux crontab. Não há diferença essencial para atingir o objetivo de reduzir o consumo de recursos do nó.

Acho que você gosta

Origin blog.csdn.net/nangonghen/article/details/109271380
Recomendado
Clasificación