Русский
Русский
English
Статистика
Реклама

Перевод Слабо поднять такой крошечный контейнер? Создаем контейнеризованный HTTP-сервер на 6kB

TL;DR я решил создать самый маленький образ контейнера, при помощи которого все-таки можно сделать что-нибудь полезное. Опираясь на преимущества многоступенчатых сборок, базового образаscratchи крошечного http-сервера на основе этой сборки, я смог ужать результат до 6.32kB!





Если предпочитаете видео, вот ролик по статье, выложенный на YouTube!

Раздутые контейнеры


Контейнеры часто превозносятся как панацея, позволяющая справиться с любыми вызовами, связанными с эксплуатацией ПО. Притом, как мне нравятся контейнеры, на практике мне часто попадаются контейнерные образы, отягощенные разнообразными проблемами. Распространенная беда размер контейнера; у некоторых образов он достигает многих гигабайт!

Поэтому я решил устроить челлендж себе и всем желающим и попытаться создать настолько компактный образ, насколько возможно.

Задача


Правила довольно просты:

  • Контейнер должен выдавать содержимое файла по http на выбранный вами порт
  • Монтирование томов не допускается (так называемое Правило Марека )

Упрощенное решение


Чтобы узнать размер базового образа, можно воспользоваться node.js и создать простой сервер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/`);});

и сделать из него образ, запуская официальный базовый образ node:

FROM node:14COPY . .CMD ["node", "index.js"]

Этот завесил на943MB!

Уменьшенный базовый образ


Один из простейших и наиболее очевидных тактических подходов к уменьшению размера образа выбрать более компактный базовый образ. Официальный базовый образ node существует в варианте slim(по-прежнему на основе debian, но с меньшим количеством предустановленных зависимостей) и вариантalpineна основеAlpine Linux.

С применениемnode:14-slimиnode:14-alpineв качестве базового удается уменьшить размер образа до167MBи116MBсоответственно.

Поскольку образы docker аддитивны, где каждый уровень надстраивается над следующим, здесь уже практически нечего сделать, чтобы еще сильнее уменьшить решение с node.js.

Скомпилированные языки


Чтобы вывести ситуацию на новый уровень, можно перейти к компилируемому языку, где гораздо меньше зависимостей времени исполнения. Есть ряд вариантов, но для создания веб-сервисов часто применяется golang.

Я создал простейший файловый серверserver.go:

package mainimport ("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)}}

И встроил его в контейнерный образ, воспользовавшись официальным базовым образом golang:

FROM golang:1.14COPY . .RUN go build -o server .CMD ["./server"]

Который завесил на818MB.

Здесь есть проблема: в базовом образе golang установлено много зависимостей, которые полезны при создании программ на go, но не нужны для запуска программ.

Многоступенчатые сборки


В Docker есть возможность под названиеммногоступенчатые сборки, с которыми просто собирать код в среде, содержащей все необходимые зависимости, а потом скопировать полученный исполняемый файл в иной образ.

Это полезно по нескольким причинам, но одна из наиболее очевидных размер образа! Выполнив рефакторинг dockerfile вот так:

### этап сборки ###FROM golang:1.14-alpine AS builderCOPY . .RUN go build -o server .### этап запуска ###FROM alpine:3.12COPY --from=builder /go/server ./serverCOPY index.html index.htmlCMD ["./server"]

Размер полученного образа всего13.2MB!

Статическая компиляция + образ Scratch


13 MB совсем неплохо, но у нас в запасе осталась еще пара трюков, позволяющих еще сильнее ужать этот образ.

Есть базовый образ под названиемscratch, который однозначно пуст, его размер равен нулю. Поскольку внутри scratchничего нет, любой образ, построенный на его основе, должен нести в себе все необходимые зависимости.

Чтобы это было возможно на основе нашего сервера на go, нужно добавить несколько флагов на этапе компиляции, чтобы обеспечить статическую линковку всех необходимых библиотек в исполняемый файл:

### этап сборки ###FROM golang:1.14 as builderCOPY . .RUN go build \-ldflags "-linkmode external -extldflags -static" \-a server.go### этап запуска ###FROM scratchCOPY --from=builder /go/server ./serverCOPY index.html index.htmlCMD ["./server"]

В частности, мы задаем externalв качестве режима линковки и передаем флаг-staticвнешнему линковщику.

Благодаря двум этим изменениям удается довести размер образа до 8.65MB

ASM как залог победы!


Образ размером менее 10MB, написанный на языке вроде Go, отчетливо миниатюрен почти для любых обстоятельств но можно сделать еще меньше! Пользовательnemasuвыложил на Github полноценный http-сервер, написанный на ассемблере. Он называется assmttpd.

Все, что потребовалось для его контейнеризации установить несколько зависимостей сборки в базовый образ Ubuntu, прежде, чем запустить предоставленный рецепт make release:

### этап сборки ###FROM ubuntu:18.04 as builderRUN apt updateRUN apt install -y make yasm as31 nasm binutilsCOPY . .RUN make release### этап запуска ###FROM scratchCOPY --from=builder /asmttpd /asmttpdCOPY /web_root/index.html /web_root/index.htmlCMD ["/asmttpd", "/web_root", "8080"]

Затем полученный в результате исполняемый файлasmttpdкопируется в scratch-образ и вызывается через командную строку. Размер полученного образа всего 6,34kB!
Источник: habr.com
К списку статей
Опубликовано: 25.04.2021 16:15:44
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании маклауд

Настройка linux

Node.js

Серверное администрирование

Go

Контейнеры

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru