scratch
dan server http kecil berdasarkan build ini, saya dapat memeras hasilnya hingga 6,32kB!
Jika Anda lebih suka video, inilah video YouTube untuk artikelnya!
Wadah kembung
Container sering disebut-sebut sebagai obat mujarab untuk menangani tantangan pemeliharaan perangkat lunak apa pun. Apalagi, karena saya suka container, dalam praktiknya saya sering menjumpai gambar container, terbebani berbagai masalah. Masalah umum adalah ukuran wadah; untuk beberapa gambar mencapai banyak gigabyte!
Jadi saya memutuskan untuk menantang diri saya sendiri dan orang lain dan mencoba membuat gambar sekompak mungkin.
Sebuah tugas
Aturannya cukup sederhana:
- Wadah harus menyajikan konten file melalui http ke port pilihan Anda
- Volume pemasangan tidak diperbolehkan (disebut "Aturan Marek")
Solusi yang disederhanakan
Untuk mengetahui ukuran gambar dasar, Anda dapat menggunakan node.js dan membuat server sederhana
index.js
:
const fs = require("fs"); const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/html' }) fs.createReadStream('index.html').pipe(res) }) server.listen(port, hostname, () => { console.log(`Server: http://0.0.0.0:8080/`); });
dan membuat gambar darinya dengan menjalankan gambar dasar resmi node:
FROM node:14 COPY . . CMD ["node", "index.js"]
Yang ini bertahan
943MB
!
Gambar dasar dikurangi
Salah satu pendekatan taktis paling sederhana dan paling jelas untuk mengurangi ukuran kulit adalah dengan memilih kulit dasar yang lebih ramping. Gambar dasar resmi node ada dalam varian
slim
(masih berdasarkan debian, tetapi dengan dependensi pra-instal yang lebih sedikit) dan varian
alpine
berdasarkan Alpine Linux .
Menggunakan
node:14-slim
dan
node:14-alpine
sebagai dasar, adalah mungkin untuk mengurangi ukuran gambar untuk
167MB
dan
116MB
sesuai.
Karena gambar buruh pelabuhan bersifat aditif, dengan setiap lapisan dibangun di atas lapisan berikutnya, hampir tidak ada yang bisa dilakukan di sini untuk mengurangi solusi node.js.
Bahasa yang dikompilasi
Untuk membawa hal-hal ke level berikutnya, Anda dapat beralih ke bahasa terkompilasi yang memiliki dependensi run-time yang jauh lebih sedikit. Ada beberapa pilihan, tetapi golang sering digunakan untuk membuat layanan web .
Saya membuat server file paling sederhana
server.go
:
package main import ( "fmt" "log" "net/http" ) func main() { fileServer := http.FileServer(http.Dir("./")) http.Handle("/", fileServer) fmt.Printf("Starting server at port 8080\n") if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } }
Dan saya membuatnya menjadi gambar kontainer menggunakan gambar dasar golang resmi:
FROM golang:1.14 COPY . . RUN go build -o server . CMD ["./server"]
Yang tergantung…
818MB
.
Ada masalah di sini: ada banyak dependensi yang terpasang di image golang dasar, yang berguna saat membuat program go, tetapi tidak diperlukan untuk menjalankan program.
Majelis multi-tahap
Docker memiliki fitur yang disebut build multistage , yang dengannya mudah untuk membuat kode di lingkungan yang berisi semua dependensi yang diperlukan, lalu menyalin file yang dapat dijalankan yang dihasilkan ke image lain.
Ini berguna karena beberapa alasan, tetapi salah satu yang paling jelas adalah ukuran gambarnya! Dengan melakukan refactoring dockerfile seperti ini:
### ### FROM golang:1.14-alpine AS builder COPY . . RUN go build -o server . ### ### FROM alpine:3.12 COPY --from=builder /go/server ./server COPY index.html index.html CMD ["./server"]
Ukuran gambar yang dihasilkan adalah segalanya
13.2MB
!
Kompilasi statis + Gambar awal
13 MB sama sekali tidak buruk, tetapi kami masih memiliki beberapa trik tersisa untuk membuatnya terlihat lebih ketat.
Ada gambar dasar yang disebut goresan , yang jelas kosong, ukurannya nol. Karena
scratch
tidak ada apa-apa di dalamnya , gambar apa pun yang dibangun di atasnya harus membawa semua dependensi yang diperlukan.
Untuk membuat ini mungkin berdasarkan server go kami, kami perlu menambahkan beberapa tanda pada waktu kompilasi untuk memastikan bahwa semua pustaka yang diperlukan ditautkan secara statis ke dalam file yang dapat dieksekusi:
### ### FROM golang:1.14 as builder COPY . . RUN go build \ -ldflags "-linkmode external -extldflags -static" \ -a server.go ### ### FROM scratch COPY --from=builder /go/server ./server COPY index.html index.html CMD ["./server"]
Secara khusus, kami menyetel
external
mode penautan dan meneruskan bendera ke
-static
penaut eksternal.
Berkat dua perubahan ini, dimungkinkan untuk memperbesar ukuran gambar
8.65MB
ASM sebagai jaminan kemenangan!
Sebuah gambar berukuran kurang dari 10MB, ditulis dalam bahasa seperti Go, secara jelas dikecilkan untuk hampir semua keadaan ... tetapi Anda dapat membuatnya lebih kecil! Pengguna nemasu telah memposting server http lengkap yang ditulis dalam assembler di Github. Ini disebut assmttpd .
Yang diperlukan untuk membuat container adalah menginstal beberapa dependensi build ke dalam image dasar Ubuntu, sebelum menjalankan resep yang disediakan
make release
:
### ### FROM ubuntu:18.04 as builder RUN apt update RUN apt install -y make yasm as31 nasm binutils COPY . . RUN make release ### ### FROM scratch COPY --from=builder /asmttpd /asmttpd COPY /web_root/index.html /web_root/index.html CMD ["/asmttpd", "/web_root", "8080"]
Eksekusi yang dihasilkan kemudian
asmttpd
disalin ke gambar awal dan dipanggil melalui baris perintah. Ukuran gambar yang dihasilkan hanya 6.34kB!