乙個僅有1KB大小的Docker容器

2021-08-19 13:07:36 字數 4357 閱讀 1151

原文:a 1 kb docker container

作者:nathan osman

翻譯:雁驚寒

摘要:本文介紹了如何使用匯程式設計序編寫乙個極小的docker容器。以下是譯文。

不,這不是打錯字,也不是玩笑。我建立了乙個docker容器,該容器包含乙個unix可執行檔案,沒有其他依賴關係,磁碟空間占用不足1kb。容器中沒有其他檔案,甚至沒有libc。

這就是證明。

在解釋如何實現這個容器之前,應該先解釋下為什麼要這麼做。 caddy-docker(這是我寫的另外乙個工具,在這裡有詳細的說明)將傳入的請求根據其標籤路由到其他執行的容器中去。

我需要用caddy-docker作為特定主機的反向**,要實現這個最簡單的方法就是啟動乙個容器,這個容器唯一的目的就是包含兩個特殊的標籤,並且容器在停止之前不應該做任何事情。

就在那個時候我想到了這個絕妙透頂的主意。

我立即開始研究這個應用程式,並因為其不尋常的目的而命名為「hang」。 go可以輕鬆生成沒有依賴關係的可執行檔案,允許docker容器從scratch繼承。唯一的缺點是,go可執行檔案相當的大,大小通常會超過8mb。

這絕對不行。

我認為,編寫乙個這樣的c程式很容易:為sigterm註冊乙個訊號處理程式,並在收到這個訊號的時候退出。不幸的是,這意味著我需要使用libc,這樣,容器很快會變得與go可執行檔案差不多大小。這根本就沒有任何優勢。

是的,生成乙個沒有依賴關係的小型可執行檔案的最快方法是用彙編編寫。我更喜歡intel風格的語法,所以,nasm是不二選擇。

曾幾何時,在x86架構出現的早些年間,系統呼叫看起來是這樣的:

mov eax, 0x01

mov ebx, 0x00

int 0x80

第一行指定要執行哪個系統呼叫 -sys_exit。第二行指定返回值(0)。第三行產生乙個核心後續會處理的中斷。

x86作業系統後來轉為使用sysenter/sysret,而x86_64則引入了乙個新的操作碼:syscall。與上面的例子類似,rax暫存器用於指定要呼叫的特定系統呼叫。上面的示例可以在x86_64程式集中進行重寫,如下所示:

mov rax, 0x3c

mov rdi, 0x00

syscall

請注意,sys_exit的系統呼叫號在x86_64上是不同的。

在c中註冊訊號處理程式很普通:

#include 

void handler(int param) {}

int main()

不幸的是,c標準庫隱瞞了以下這幾件事情:

我們不能直接將c**轉換成彙編,因為sigaction的結構與sys_rt_sigaction所期望的不一致。以下是nasm中核心結構的樣子:

struc sigaction

.sa_handler resq 1

.sa_flags resq 1

.sa_restorer resq 1

.sa_mask resq 1

endstruc

每個成員的大小為8位元組。

首先,我們必須在.bss段中為該結構體分配空間:

section .bss

act resb sigaction_size

請注意,sigaction_size是匯程式設計序為我們建立的特殊值 - 它等於sigaction的大小(以位元組為單位)。然後可以在.text段中初始化該結構體,如下所示:

section .text

global _start

lea rax, [handler]

mov [act + sigaction.sa_handler], rax

mov [act + sigaction.sa_flags], dword 0x04000000

; sa_restorer

lea rax, [restorer]

mov [act + sigaction.sa_restorer], rax

handlerrestorer這兩個標籤我們稍後會提到。現在我們可以呼叫sys_rt_sigaction這個系統呼叫了:

mov rax, 0x0d

; sys_rt_sigaction

mov rdi, 0x0f

; sigterm

lea rsi, [act]

mov rdx, 0x00

movr10, 0x08

syscall

mov rax, 0x22  ; sys_pause

syscall

處理程式本身很普通,它沒有做任何事情:

handler:

ret

恢復器(restorer)也很簡單,雖然它需要呼叫sys_rt_sigreturn系統呼叫:

restorer:

mov rax, 0x0f

; sys_rt_sigreturn

syscall

需要兩個命令來構建應用程式。假定原始檔名為hang.asm,則命令是:

nasm -f elf64 hang.asm

ld -s -o hang hang.o

這將產生乙個名為hang的可執行檔案,它很小:

$ stat hang

file

: hang

size

:736

是的,它只有736位元組。

dockerfile相當簡單,只需要兩個命令:

from scratch

add hang /usr/bin/hang

entrypoint ["/usr/bin/hang"]

我們來看看容器是否能工作:

$ docker build -t nathanosman/hang .

$ docker run -d --name hang nathanosman/hang

此時,容器應該保持執行狀態:

$ docker ps -a

container id image command status

f1861f628ea8 nathanosman/hang "/usr/bin/hang" up 3

seconds

當執行docker stop時,應該立即停止:

$ docker stop hang

hang

有用!我們來確認以下容器的大小是否和可執行檔案的大小一致:

$ docker images

repository

tagcreated

size

nathanosman/hang latest 2 minutes ago 736b

是的!乙個非常小的容器!

你可以在這裡找到源**:

2023年10月14日,sdcc 2017之大資料技術實戰線上峰會即將召開,邀請圈內頂尖的布道師、技術專家和技術引領者,共話大資料平台構建、優化提公升大資料平台的各項效能、spark部署實踐、企業流平台實踐、以及實現應用大資料支援業務創新發展等核心話題,七位大牛與你相聚狂歡,詳情檢視所有嘉賓和議題,以及註冊參會,分享還可優惠30元。

PHP實現讀取乙個1G的檔案大小

需求如下 現有乙個1g左右的日誌檔案,大約有500多萬行,用php返回最後幾行的內容。1.直接採用file函式來操作 or file get content 肯定報記憶體溢位 注 由於 file函式是一次性將所有內容讀入記憶體,而php為了防止一些寫的比較糟糕的程式占用太多的記憶體而導致系統記憶體不...

李彥巨集 創業僅僅有乙個好主意是不夠的

創業董事長兼ceo李彥巨集昨日應邀至上海交通大學演講,並與該校師生圍繞 創業與個人發展 進行了熱烈的互動。並非拿到錢就是好事 公司指數 但出人意料的是,在昨天的演講中,這位被學子們認為未來創業最好的 學習推廣 這一商業模式時,李彥巨集表示,確立這個商業模式,是歷經幾年摸索才得以逐漸明晰下來的。三個發...

看乙個物件的佔記憶體大小

pragma pack 8 includeusing namespace std class a class b class c class d 0 class e 4 virtual指標 vptr 8 系統是64位,8 8,故指標位元組數8 8 8 8 24 int main int argc,c...