天天看點

自定義一個kaniko鏡像背景遇到的難題解決方案示例代碼

背景

kaniko是一款友善我們從K8S内部建構docker容器的工具,以前我們在CI過程中,使用的是docker-in-docker技術,這種技術最主要的缺陷就是當一台機器上同時運作多個docker build流水線時,會出現阻塞的情況,因為這一批流水線用的是主控端上的同一個docker程序。

基于這種情況,我們在droneCI流水線中換用了kaniko來進行docker鏡像的建立。

遇到的難題

  1. kaniko是基于scratch建構的,裡面沒有shell,是以想在kaniko原生鏡像裡在調用python是很麻煩的
  2. kaniko建立docker鏡像使用的是file system功能,如果想在一個kaniko容器裡先建立ubuntu鏡像,再建立alpine鏡像, 是會有各種沖突問題的,需要使用–cleanup功能。此功能會清空檔案系統,同時如果有自己裝的shell,也會被清空,導緻無法再次使用

解決方案

  1. kaniko的關鍵檔案其實是/kaniko目錄下的哪些 二進制檔案,官方推薦是用gcr.io/kaniko-project/executor 鏡像,其實我們可以拷貝這個/kaniko目錄到我們自己的私有鏡像
  2. shell沒有的話,我們可以拷貝一個busybox進去,這樣就有shell了
  3. 雖然–cleanup會清空file system,但是根據代碼裡的ignorepath設定,volume挂載目錄和/kaniko目錄會被忽略掉。是以我們可以有兩種方式選擇:一、通過volume的方式哦挂載busybox和自己的python代碼到私有鏡像裡。二、把busybox和python代碼加入/kaniko目錄。

示例代碼

Dockerfile如下:

FROM heiheidoc/kaniko-project-executor:v1.3.0 AS plugin
# 1.6.0的clean up有問題 https://github.com/GoogleContainerTools/kaniko/issues/1586
FROM heiheidoc/kaniko-project-executor:debug AS debug
FROM python:3.9.5-buster
COPY --from=背景plugin /kaniko /kaniko
COPY --from=debug /busybox /kaniko/busybox
ADD . /kaniko
ENV DOCKER_CONFIG /kaniko/.docker
CMD ["python3","/kaniko/main.py"]      

部分python代碼如下,功能是按照一定規則生成Docker鏡像:

def run_shell(shell):
    print_green(shell)
    cmd = subprocess.Popen(shell, stdin=subprocess.PIPE, stderr=sys.stderr, close_fds=True,
                           stdout=sys.stdout, universal_newlines=True, shell=True,executable='/kaniko/busybox/sh', bufsize=1)
    cmd.communicate()
    return cmd.returncode
def run_executor():
    for folder_name, sub_dir, files in os.walk(os.getcwd()):
        if 'Dockerfile' in files:
            Dockefile_path = folder_name + "/Dockerfile"
            docker_info = folder_name.replace(os.getcwd(),'').split('/')
            harbor_image_name = REGISTRY_URL + "/" + owner_name + "/" + docker_info[1] + ":" + docker_info[2]
            cmd_build = "/kaniko/executor --cache=true --cache-dir=/cache --cleanup --skip-tls-verify --skip-tls-verify-pull --skip-tls-verify-registry" \
                        " --dockerfile=" + Dockefile_path + \
                        " --context=dir://" + folder_name + \
                        " --destination=" + harbor_image_name
            assert run_shell(cmd_build) == 0, "鏡像build失敗: " + harbor_image_name
if __name__ == "__main__":
    run_executor()