我的docker隨筆25:一個測試用的鏡像製作過程

本文記錄製作一個鏡像的過程,先構建可運行靜態程序的鏡像,以此爲基礎,構建一個golang語言編寫的web服務器,可獲取容器的主機、內核版本等信息。該鏡像可用於 k8s 和 KubeEdge 羣集測試。

環境說明

安裝docker,登陸到dockerhub。
安裝golang編譯器,用於編譯源碼。
安裝 qemu,用於在 x86 平臺上運行 arm 版本容器。如無此需求,可忽略。

sudo apt install qemu-user-static

基於manifest製作鏡像,適用於 x86 和 arm 平臺。
注意,這裏說的 x86,實際是64位系統,應該稱爲amd64,說 x86 僅是習慣而已,非錯誤。但 arm 平臺,是指 32 位系統,因筆者暫無 64 位系統,後續再完善。

鏡像設計

如下:

latelee/busybox  這是對外使用的鏡像名稱,根據不同平臺自動匹配下載
latelee/busybox-arm
latelee/busybox-amd64

latelee/webgin 
latelee/webgin-arm
latelee/webgin-amd64

基礎鏡像

官方busybox支持衆多平臺,但默認的版本沒有一些依賴文件。但glibc版本有。
下面從實踐角度描述如何製作。

製作x86平臺基礎鏡像

下載:

docker pull busybox

製作如下:

運行:
docker run -itd --name busybox busybox
創建目錄:
docker exec -it busybox mkdir -p /lib/x86_64-linux-gnu /lib64
拷貝運行庫、鏈接器:
docker cp -a /lib/x86_64-linux-gnu/libpthread.so.0 busybox:/lib/x86_64-linux-gnu
docker cp -a /lib/x86_64-linux-gnu/libpthread-2.23.so busybox:/lib/x86_64-linux-gnu
docker cp -a /lib/x86_64-linux-gnu/libc-2.23.so  busybox:/lib/x86_64-linux-gnu
docker cp -a /lib/x86_64-linux-gnu/libc.so.6  busybox:/lib/x86_64-linux-gnu
docker cp -a /lib64/ld-linux-x86-64.so.2 busybox:/lib64/
docker cp -a /lib/x86_64-linux-gnu/ld-2.23.so busybox:/lib/x86_64-linux-gnu/

保存爲鏡像
docker commit busybox latelee/busybox-amd64

測試(預期結果有上述文件輸出)
docker run -it --rm latelee/busybox-amd64 ls -lh /lib/x86_64-linux-gnu /lib64

提交:

docker push latelee/busybox-amd64

製作arm平臺基礎鏡像

在一塊安裝了 docker 的 arm 板子上執行:

docker pull busybox

注:該命令與上述完全相同,因其系統不同,dockerhub自動匹配到合適的並下載。在真實機器上是爲了確保鏡像的可靠性。

製作如下:

運行:
docker run -itd --name busybox busybox
創建目錄:
docker exec -it busybox mkdir -p /usr/lib/ /lib
拷貝運行庫、鏈接器:
docker cp /lib/ld-2.25.so busybox:/lib/
docker cp /lib/ld-linux-armhf.so.3 busybox:/lib/
docker cp /usr/lib/libpthread-2.25.so busybox:/usr/lib
docker cp /usr/lib/libpthread.so.0 busybox:/usr/lib
docker cp /usr/lib/libc.so.6 busybox:/usr/lib/
docker cp /usr/lib/libc-2.25.so busybox:/usr/lib/

保存爲鏡像
docker commit busybox latelee/busybox-arm

測試(預期結果有上述文件輸出)
docker run -it --rm latelee/busybox-arm ls -lh /usr/lib/ /lib

提交:

docker push latelee/busybox-arm

使用glibc版本

直接使用busybox:glibc版本製作,無法額外拷貝文件。在 x86 上執行:

docker pull busybox:glibc
docker tag busybox:glibc latelee/busybox-amd64

在 arm 上執行:

docker pull busybox:glibc
docker tag busybox:glibc latelee/busybox-arm

注:筆者使用前面小節的方法,glibc版本可能後續更新。

在 x86 上運行 arm 版本容器

有時不方便在 arm 板子上運行,則可以在 x86 上模擬之。
掛載 qemu-arm-static 文件:

docker run -it --rm -v /usr/bin/qemu-arm-static:/usr/bin/qemu-arm-static latelee/busybox-arm ls -lh /usr/lib/ /lib

另一方法,運行 qemu-user-static 容器,再運行 arm 容器:

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker run -it --rm latelee/busybox-arm ls -lh /usr/lib/ /lib

多平臺支持

技術要點:開啓docker實驗功能,預先提交不同平臺的鏡像到dockerhub上,創建manifest,推送。

export DOCKER_CLI_EXPERIMENTAL=enabled

docker manifest create latelee/busybox latelee/busybox-amd64 latelee/busybox-arm

docker manifest annotate latelee/busybox latelee/busybox-amd64 --os linux --arch amd64
docker manifest annotate latelee/busybox latelee/busybox-arm --os linux --arch arm

查看:
docker manifest inspect latelee/busybox

推送:
docker manifest push latelee/busybox

webgin

webgin 是指用 gin 框架編寫的 web 服務,開放80端口,可輸出主機信息。其構建方式與上述類似,不再贅述。webgin.go源碼如下:

package main

import (
    "fmt"
    "runtime"
    "os"
    "time"
    "github.com/gin-gonic/gin"
    "net/http"
)

// uname

/*
#include <stdio.h>
#include <sys/utsname.h>

char* GetName()
{
    arch := fmt.Sprintf("arch: %s os: %s hostname: %s\r\n", runtime.GOARCH, runtime.GOOS, hostname)
    struct utsname myname;
    static char buffer[128] = {0};
    uname(&myname);
    
    snprintf(buffer, 128, "uname: %s %s %s %s %s\r\n", myname.sysname, 
                    myname.nodename, myname.release, 
                    myname.version, myname.machine);
    return buffer;
}
*/
import "C"

var version = "v1.0"

func myIndex (c *gin.Context) {
    uname := C.GetName()
    name := C.GoString(uname)
    hostname, _ := os.Hostname()
    arch := "arch: " + runtime.GOARCH + " os: " + runtime.GOOS + " hostname: " + hostname + "\r\n";
    timeStr := "Now: " + time.Now().Format("2006-01-02 15:04:05") + "\r\n"
    c.String(http.StatusOK, "Hello World " + version + "\r\n" + arch + name + timeStr)
}

func main(){
    router := gin.Default()
    router.GET("/", myIndex)
    fmt.Println("gin server start...")
    router.Run(":80")
}

構建腳本:

#!/bin/sh

export GOARCH=amd64
export GOOS="linux"
export GOARM= 
export CGO_ENABLED=1
export CC=gcc
GO111MODULE=off go build
strip webgin
docker build -t latelee/webgin-amd64 . -f Dockerfile

export GOARCH=arm
export GOOS="linux"
export GOARM=7 
export CGO_ENABLED=1
export CC=arm-linux-gnueabihf-gcc
GO111MODULE=off go build
arm-linux-gnueabihf-strip webgin
docker build -t latelee/webgin-arm . -f Dockerfile.arm

dockerfile:

From latelee/busybox-amd64

LABEL maintainer="Late Lee"

COPY webgin /

EXPOSE 80

CMD ["/webgin"]

運行:

docker run -it --name webgin --rm -p 80:80 latelee/webgin

測試:

# curl localhost:80
Hello World v1.0
arch: amd64 os: linux hostname: 60acfd65857a
uname: Linux 60acfd65857a 4.4.0-174-generic #204-Ubuntu SMP Wed Jan 29 06:41:01 UTC 2020 x86_64
Now: 2020-03-26 23:10:36

依賴文件確認

缺少鏈接器:
/ # ./webgin 
sh: ./webgin: not found
其它:
/ # /webgin 
/webgin: error while loading shared libraries: libpthread.so.0: cannot open shared object file: No such file or directory

/ # /webgin 
/webgin: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory

如果官方 dockerhub 速度慢,可選用阿里雲容器鏡像服務。其企業版本已於2020年3月中旬商業化,個人版不太清楚。
登陸阿里雲倉庫:sudo docker login [email protected] registry.cn-hangzhou.aliyuncs.com
已完成版本:

registry.cn-hangzhou.aliyuncs.com/latelee/webgin  版本:v1.0 v1.1 v1.2
registry.cn-hangzhou.aliyuncs.com/latelee/busybox
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章