Konttien Big Bang

Docker-kontit ovat nyt ja tulevaisuudessa tietojärjestelmien peruskauraa. Konttiekosysteemillä testataan, jaetaan ja ajetaan sovelluksia laidasta laitaan. Konttien ekosysteemi koostuu kolmesta komponentista: konteista, konttien ajon hallitsevasta sovelluksesta kuten Docker ja kontti-rekistereistä. Konttien perusyksikkönä on siis kontti, tarkemmin sanottuna kontin levykuva.

Kontti on vakioitu, kapseloitu ja muusta maailmasta lähtökohtaisesti täysin eristetty ympäristö, jossa ajetaan konttiin asennettua sovellusta. Niiden perustana olevassa levykuvassa on ajettava sovellus ja sen riippuvuudet. Kontit ovat tunnistettavissa yksilöllisellä SHA-256-tarkistussummalla, joka lasketaan levykuvan perusteella. Kaikki muutokset konttiin muuttavat levykuvaa ja siten tarkistussummaa.

Kontit luodaan erikseen kutakin tarvetta varten. Tyypillisesti esimerkiksi sovellusprojektissa, jossa käytetään Pythonia, kontti luodaan käyttäen Python-projektin julkiseen Docker Hub-rekisteriin julkaisemaa konttia. Konteista valitaan projektiin soveltuva versio, esimerkiksi python, python:slim-bullseye tai python:3.9.15-slim-buster.

Luotaessa omaa Python-sovellusta varten konttia, käytetään esimerkiksi jotain edellä mainituista konteista pohjana. Siihen lisätään omat sovellukset. Alla olevassa esimerkissä käytetään pohjana tuoreinta Python-projektin konttia. Konttiin kopioidaan paikallisesta hakemistosta tiedosto run ja kerrotaan että oletuksena kontin käynnistyessä ajetaan sovellus run parametrilla app.

FROM python
COPY run .
CMD ["run", "app"]

Uudet kontit siis rakennetaan vanhojen konttien päälle. 

Mitä python-kontti pitää sisällään?

Tämän mysteerin selvittämisessä auttaa Python-projektin konttien tagien arvoissa olevat maininnat ”slim-bullseye” ja ”slim-buster”. Ne tulevat Debian GNU/Linux-jakelupaketin versioista ”Buster” ja ”Bullseye”. Python-projekti siis julkaisee kontteja ainakin kahdella eri Debian versiolla.

Python-projektimme buster-slim-kontti luodaan Debian-projektin julkaiseman buster-slim-kontin päälle. Tämän voi tarkistaa katsomalla esimerkiksi Python 3.10 Dockerfilen ensimmäisen komennon, joka on FROM debian:buster-slim .

Entä juurikontti?

Esimerkki juurikontin luomisesta löytyy Debian-projektin konteista. Erityisen hyvä esimerkki on mielestäni Dockerfile buster-slim-kontille:

FROM scratch
ADD rootfs.tar.xz /
CMD ["bash"]

Debian-projektin Dockerfilessä käytetään FROM-komennon erikoisarvoa ”scratch”. Sillä kerrotaan docker build -komennolle että levykuvalle tuodaan sisältö muualta ja se tehdäänkin heti seuraavalla rivillä komennolla ”ADD rootfs.tar.xz”. Koska komento ADD purkaa parametrina tiedoston automaattisesti jos se tunnistetaan pakatuksi, ”rootfs.tar.xz”:n sisältämät tiedostot puretaan kontin juureen.

Kontin luomisen ensimmäinen askel on siis tuoda tarvitut tiedostot kontin ulkopuolelta. Tiedostojen valinta on kiinni täysin käyttötarkoituksesta. Tyypillisesti kontin perustiedostojen lähteenä on tietyn Linux-jakelupaketin tietyn version ajantasaiset kirjastot. Esimerkiksi Debian-projektin ajantasaiset kirjastot ovat saatavilla projektin itse julkaisemina suoraan heidän palvelustaan.

Docker-konteista siis tehdään kuhunkin tarkoitukseen yksilöllisiä ja siten erikokoisia kontteja. Natiivibinääriksi staattisesti käännetty sovellus ei lisäkirjastoja tarvitse, kun taas dynaamisemmat, esimerkiksi Javalla kirjoitetut sovellukset, tarvitsevat paljon kirjastoja. Niiden kontit ovatkin sitten kookkaampia. Tietoturvallisuuden, energiansäästön ja muun resurssikulutuksen takia binääriksi käännettävät kielet kuten Go ja Rust ovat kiinnostavia, koska niistä syntyvän sovelluksen kontin koko on merkittävästi pienempi.

Kontteja valittaessa ja käytettäessä on tärkeää tiedostaa se prosessi mikä konttien luomiseen liittyy. Jälkikäteen on lähes mahdotonta selvittää kenen toimesta ja miten Docker-kontti on luotu. Paneudun konttien tietoturvaan tulevassa blogissani myöhemmin syksyllä. Lisää konteista voit lukea sarjan ensimmäisestä blogikirjoituksesta.