Formát opkg
Tento formát má za sebou zajímavou historii. Kdysi vznikl formát .ipkg
kterýž se používal na handheldech s Linuxem. Pro mladší čtenáře, jednalo se o zařízení připomínající dnešní chytrý telefon, jen to nemělo telefon a často ani foťák. Formát se v embedded komunitě ujal, měl však jeden zásadní problém. Jméno. To bylo zaregistrováno jako ochranná známka. Ač byl software pod licencí GNU GPL, nebylo možné rozumně balíčkovací systém dále rozvíjet a používat, a tak vznikl opkg
jako jeho fork.
Byl používán různými distribucemi, z nichž dodnes zbyly dvě: OpenEmbedded a OpenWrt. Každá z nich se ke svému forku chovala trochu jinak. OpenWrt svoje opkg
osekávalo, aby bylo co nejmenší a v rámci toho se například stahování balíčků z repozitářů stále provádí přes externí program a obecně jeho vývoj po osekání na základní minimum ustal. Oproti tomu opkg
používaný v OpenEmbedded se rozšiřoval o další možnosti: podporuje stahování balíčků samo o sobě, dokáže podporovat kontrolování podpisů PGP a má i mnoho dalších funkcí oproti svému chudšímu bratříčkovi z OpenWrt. Také ale balíčkovací systém narostl na velikosti, nejen na schopnostech.
Pojďme se ještě podívat, jak balíčky opkg
vypadají uvnitř. Ve skutečnosti jsou strukturou velmi podobné debianím balíčkům. Každý balíček je vlastně tarball. Když si ho rozbalíte, zjistíte, že uvnitř jsou další dva tarbally a soubor debian-binary
specifikující verzi formátu balíčku. Tarbally se jmenují výmluvně control.tar.gz
a data.tar.gz
. Data je samotný obsah balíčku – binárky, knihovny a podobně včetně celé adresářové struktury. Control je zajímavější – ten obsahuje například postinstalační skripty nebo další metadata. Obsah souboru vypadá nějak takhle:
Package: opkg
Version: 2022-02-24-d038e5b6-2
Depends: libc, uclient-fetch, libpthread, libubox20230523
Source: feeds/base/package/system/opkg
SourceName: opkg
License: GPL-2.0
LicenseFiles: COPYING
Section: base
SourceDateEpoch: 1684402529
Essential: yes
Maintainer: Jo-Philipp Wich <jo@mein.io>
Architecture: aarch64_cortex-a53
Installed-Size: 73078
Description: Lightweight package management system
opkg is the opkg Package Management System, for handling
installation and removal of packages on a system. It can
recursively follow dependencies and download all packages
necessary to install a particular package.
opkg knows how to install both .ipk and .deb packages.
Samotný balíčkovací systém poté na routeru pracuje hlavně s adresářem /usr/lib/opkg
, kde nalezneme opět hezky textový soubor status
obsahující seznam nainstalovaných balíčků i se závislostmi. V podadresáři info
nalezneme jak výše zmiňovaný soubor control
pro každý nainstalovaný balík, tak postinstalační skripty, seznamy souborů nebo třeba kontrolní součty všech souborů, které balíček nainstaloval.
Původně, když se to ještě jmenovalo ipkg
, to byla jen sada skriptů a dodnes jsou všechny informace v textových souborech a relativně snadno zpracovatelné shellovými skripty.
Jelikož článek vznikl jako reakce na změnu ohlášenou v OpenWrt, budu dál porovnávat verzi opkg
právě z projektu OpenWrt.
Formát apk
Tento formát vznikl přímo pro distribuci Alpine Linux a nemá tak zajímavou historii jako opkg
. Pojďme se tedy rovnou podívat na jeho vnitřnosti. Formát apk
není tak jednoduchý jako opkg
. Nerozbalíte si balíček úplně snadno ručně a taktéž jeho manuální úprava není snadná.
Každý balíček se skládá ze tří streamů gzip, ve kterých jsou dva segmenty tar a jeden tarball. Streamy jsou jen poskládané za sebe, není zde žádný zastřešující tarball jako u opkg
. Pokud budete chtít balíček rozbalit bez apk
, nebude to už tak snadné.
Co se skrývá uvnitř? Jedna část je opět adresářová struktura se všemi soubory. Ta navíc v PAX headerech obsahuje kontrolní součty všech souborů – metadata, která se vám budou jen těžko ručně generovat a zároveň i využívat. Další tar jsou metadata balíčku, opět se jedná o různé skripty a soubor s metadaty. Tentokrát s názvem .PKGINFO
. I ten si můžeme ukázat:
pkgname = apk-tools
pkgver = 2.14.6-r2
pkgdesc = Alpine Package Keeper - package manager for alpine
url = https://gitlab.alpinelinux.org/alpine/apk-tools
builddate = 1733238076
packager = Buildozer <alpine-devel@lists.alpinelinux.org>
size = 253640
arch = x86_64
origin = apk-tools
commit = 85fce5ac38cd9990b8910637d750591e3ef55a6c
maintainer = Natanael Copa <ncopa@alpinelinux.org>
license = GPL-2.0-only
depend = musl>=1.2.3_git20230424
depend = ca-certificates-bundle
# automatically detected:
provides = so:libapk.so.2.14.0=2.14.0
provides = cmd:apk=2.14.6-r2
depend = so:libc.musl-x86_64.so.1
depend = so:libcrypto.so.3
depend = so:libssl.so.3
depend = so:libz.so.1
datahash = ff1d1c786dbdb4d2df78de548ada01c8d1c5aee74fdf6d03c9a43e2628a5459f
Obsahově nevypadá zas až tak odlišně od souboru control
, který používá opkg
. Čeho je dobré si zde všimnout je, že na rozdíl od opkg
je tu haš datové části balíčku a tak balíček sám o sobě nese v metadatech způsob, jak zkontrolovat, že není poškozený.
Aby toho nebylo málo, poslední kousek taru, o kterém jsme doposud nemluvili, obsahuje podpis. Je to soubor pojmenovaný .SIGN.RSA.<keyname>.rsa.pub
, kde keyname je jméno klíče nacházejícího se v /etc/apk/keys
. Tedy každý jednotlivý balíček je explicitně podepsaný a lze si ověřit, že pochází z důvěryhodného zdroje, ať už k nám doputoval jakkoliv. Zároveň má u sebe uvedeno, jakým klíčem se má ověřovat podpis a tak vidíme, kdo že to prý balíček podepsal.
Repozitáře
Když jsem psal o tom, jak si můžeme ověřit původ balíčků apk
, jak se to vlastně dělá u balíčků opkg
? Tam v souboru control
sice máme velikost, ale nic víc. Odpovědí jsou zde repozitáře a jejich indexy. Každý repozitář opkg
obsahuje soubor Packages
(případně v komprimované podobě Packages.gz
), který obsahuje seznam všech balíčků v repozitáři včetně jejich metadat, mimo jiné i velikostí a kontrolních součtů. Typicky bývá součástí i soubor Packages.sig
, který obsahuje podpis souboru Packages
. Poskládáme-li si všechny informace dohromady, dokážeme pak ověřit pravost balíčku.
Záznam v indexu vypadá následovně:
Package: opkg
Version: 2022-02-24-d038e5b6-2
Depends: libc, uclient-fetch, libpthread, libubox
License: GPL-2.0
Section: base
Essential: yes
Architecture: arm_cortex-a9_vfpv3-d16
Installed-Size: 71431
Filename: opkg_2022-02-24-d038e5b6-2_arm_cortex-a9_vfpv3-d16.ipk
Size: 72817
SHA256sum: c55fccc2810c5874657dd61f6d8a4caffe2a752fbbbd7c0ced6d37a20b0da503
Description: Lightweight package management system
opkg is the opkg Package Management System, for handling
installation and removal of packages on a system. It can
recursively follow dependencies and download all packages
necessary to install a particular package.
U apk
máme také repozitáře. Je zde jen jeden soubor pro index – APKINDEX.tar.gz
. Ten obsahuje APKINDEX
s podobnými informacemi jako Packages
soubor u opkg
a je o něco málo méně čitelný. Ale součástí taru je také opět podpis klíčem ve stejném formátu, jako u balíčků samotných. Tedy krom toho, že si ověříme podpis u jednotlivých balíčků, můžeme si zkontrolovat i podpis celého repozitáře a odtud vyčíst kontrolní součty pro jednotlivé balíčky. Navíc nám stačí jen jeden soubor. Záznamy v něm vypadají následovně:
C:Q106jGcB9LDzSMGlek2CvrpT0XVjI=
P:apk-tools
V:2.14.6-r2
A:x86_64
S:122055
I:253640
T:Alpine Package Keeper - package manager for alpine
U:https://gitlab.alpinelinux.org/alpine/apk-tools
L:GPL-2.0-only
o:apk-tools
m:Natanael Copa <ncopa@alpinelinux.org>
t:1733238076
c:85fce5ac38cd9990b8910637d750591e3ef55a6c
D:musl>=1.2.3_git20230424 ca-certificates-bundle so:libc.musl-x86_64.so.1 so:libcrypto.so.3 so:libssl.so.3 so:libz.so.1
p:so:libapk.so.2.14.0=2.14.0 cmd:apk=2.14.6-r2
Velikost
Běžným lidem na velikosti zase až tolik nezáleží (jinak by nebyly tak populární Dockery, Flatpaky a podobné moderní vymoženosti), ale pro OpenWrt je velikost na prvním místě a pro Alpine je to také důležitý parametr. Pojďme se tedy podívat, jak si správci balíčků vedou ve srovnání. Hlavní binárka apk
má jen 56 kB. Oproti tomu opkg
má 148 kB. Na druhou stranu apk
má ve svém balíčku ještě libapk
, která přidá dalších 164 kB. Ve finále nám tak apk
na routeru zabere o drahocenných 72 kB více.
Ale to není vše. Podívejme se na další závislosti. V případě opkg
je seznam knihoven krátký – je tam jen libubox
. To je jedna ze základních knihoven v OpenWrt, používá ji například init systém procd
, takže se bez ní asi neobejdete. U apk
je seznam delší. Mezi závislostmi nalezneme SSL knihovnu, zlib
a libatomic
. Bez SSL, to je dalších 112 kB navíc. Pokud započítáme SSL, tak toho místa bude potřeba o hodně víc, v případě MbedTLS dokonce 424 kB. Nástroj opkg
má sice méně závislostí, ale zase závisí na runtime binárkách, jako třeba uclient-fetch
, která se používá pro stahování balíčků a zabírá 48 kB.
Co se místa týče, přechod z opkg
na apk
vás tedy může stát až 560 kB navíc. Což nezní jako mnoho, ale pro zařízení, která mají 32MB paměť flash, to může být citelný rozdíl. I když ruku na srdce, SSL knihovnu a zlib na routeru většinou chcete tak jako tak a pak se už velikosti srovnají. Ale získáme výměnnou za potencionálně draze zaplacené místo nějakou výhodu?
Vlastnosti
Oba systémy zvládnou základní práci s balíčky. Konkrétní příkazy budou vypadat poněkud jinak, viz tabulka na konci článku, ale na to si uživatelé časem zvyknou. Umí však apk
něco, co opkg
nezvládne, nebo zvládne, ale špatně?
Audit
Zajímavá funkce integrovaná v apk
je možnost auditu. Jelikož mezi metadaty každého balíčku je i seznam souborů s patřičnými haši, lze snadno zkontrolovat, jestli došlo k poškození nebo záměrnému pozměnění souboru na disku oproti stavu zaznamenaném v metadatech balíčku.
V případě opkg
lze podobnou funkcionalitu simulovat pomocí shellového skriptu, ale integrované přímo ve správci balíčků to je rychlejší a více po ruce.
Přístup k upgrade a obecně stavu systému
U OpenWrt není upgrade úplně jednoduchou operací. Typická instalace OpenWrt spočívá ve vysoce komprimovaném obrazu SquashFS a nad tím je overlay a připojený nějaký další souborový systém pro doplnění několika dalších balíčků. Pokud tam máte pár balíčků v overlay a chcete aktualizovat jen ty, tak to s trochou opatrnosti a po jednom jde.
Pokud chcete aktualizovat vše, tak je to složitější. Již před lety byl v opkg
odstraněn příkaz upgrade-all
a dokonce existuje i stránka na wiki, kde se popisuje, že uživatele by neměli upgradovat – alespoň tedy ne pomocí opkg
. Pomineme-li celý overlayovaný souborový systém a problémy z něj vycházející při update základních součástí systému, máme tu i další problémy.
Jedna z nevýhod opkg
je jeho využívání externích programů a instalace balíčků hned po jejich stažení. Snadno se tak stane, že si v rámci aktualizace závislostí aktualizujete nějakou základní knihovnu (libc, libubox, OpenSSL), a pak už není možné spustit příkaz na stažení dalšího balíčku, protože programu pro stahování balíčků chybí knihovna. Balíčkovací systém opkg
pak vesele vyhlásí chybu a skončí a nechá vás to vyřešit. Vy jste ale ve stavu, kdy nedokážete nejen stáhnout balíček, ale může se stát, že už ani opkg
znovu nespustíte.
Jedna z velkých výhod apk
je jeho celkově lepší přístup ke správě systému. Vše se zde točí kolem souboru /etc/apk/world
. Příkazy jako apk add
jen modifikují tento soubor a následně se snaží uvést systém do konzistentního stavu. Zmíněný soubor obsahuje všechny balíčky a jejich omezení (například na verzi), které mají být nainstalovány v systému.
Po svém spuštění se apk
jen snaží dostat systém do konzistentního stavu se stavem světa (worldu). Pokud konzistence docílit lze, apk
instaluje a maže balíčky, aby tohoto stavu bylo dosaženo. Pokud cestu nevidí, vzdá to předem. Proti tomu opkg
se snaží provést jednu konkrétní operaci a jen při ní kontroluje závislosti a konflikty. Případné řešení a hledání cesty už je na uživateli.
Finále?
Jak se mi při porovnání balíčkovací systémy zamlouvaly? U apk
je vidět, že ač mladší, je to dospělejší balíčkovací systém. Umí toho více než samotnéopkg
a je na něj větší spolehnutí. Jediné výhodyopkg
jsou velikost a „jednoduchost“. Lze si snadno balíček stvořit i ručně, stejně jako repozitář. Na druhou stranu, jakmile chceme s balíčky pracovat, narazíme na jiný druh jednoduchosti, který nám bude život spíše ztěžovat.
Co na to Turris OS?
Problémy a omezení opkg
nás v Turrisu vedly k napsání našeho vlastního updateru. Ten opkg
nepoužívá, ale rozumí jeho balíčkům. Stahuje i rozbaluje vše sám a vždy tedy doinstaluje, co je potřeba. Funguje podobně jako apk
– také si udržuje jakýsi seznam balíčků, které mají být na systému nainstalované. Jen je ten seznam trochu složitější. Je psaný v jazyce Lua a tak nám to umožňuje psát třeba i cykly a podmíněné závislosti.
Zároveň podporuje priority a závislosti na hardware – když detekuje podporovanou kartu, doinstaluje vám ovladače. Navíc ho jeho část žije na našich serverech. To nám umožňuje řešit migrace a uživatelské požadavky na vyšší úrovni než v jednotlivých balíčcích.
Přechod na apk
nám umožní nezabývat se tolik tím, jak nainstalovat samotné balíčky. Můžeme zahodit naší interní implementaci opkg
a soustředit se „jen“ na správu „worldu“. Samozřejmě to bude vyžadovat hromadu práce, ale věříme, že to zároveň přinese i spoustu benefitů nejen pro nás.
Tabulka srovnání příkazů opkg
a apk
Funkce | opkg | apk |
---|---|---|
Instalace balíčku | opkg install <pkg> | apk add <pkg> |
Odinstalace balíčku | opkg remove <pkg> | apk del <pkg> |
Aktualizace dat z repa | opkg update | apk update |
Vyhledávání balíčku | opkg list <glob> | apk search <glob> |
Kontrola nainstalovaných balíčků | pkg_check | apk audit |
Oprava konzistence v závislostech | – | apk fix |
Aktualizace celého systému | sysupgrade? | apk upgrade |