Kako zgraditi minimalne vsebnike Docker za aplikacije Python

Blog

Kako zgraditi minimalne vsebnike Docker za aplikacije Python

Kako zgraditi minimalne vsebnike Docker za aplikacije Python

  1. Uporabi večstopenjska gradnja
  2. Prva stopnja namesti sistemske odvisnosti in jih uporablja za izdelavo lokalnih koles
  3. Stopnja 2 se začne z iste podlage kot stopnja 1, kopira kolesa iz stopnje 1 in namesti kolesa
    4. Preostanek vaše gradnje bo temeljil na 2. stopnji

Če sledite tem korakom, boste na koncu dobili najmanjši možni vsebnik Python Docker z vsemi nedotaknjenimi odvisnostmi Pythona.



Opomba: ta objava se nanaša na Docker 18.03, Python 3.6 in pip 10. Predvidevam, da uporabljate CPython (Referenčna izvedba Pythona).

Težava

Z Dockerjem želimo zgraditi sistem Python. Zgradbe sistema Python pogosto zahtevajo namestitev kode drugih proizvajalcev. Koda tretje osebe lahko vsebuje kodo ali vire, ki jih je treba sestaviti med namestitvijo. Zaradi poenostavitve predpostavimo, da govorimo o izvorni kodi v programskem jeziku C. Ker bo vsebnik Docker naš ciljni stroj, bomo v našem vsebniku Docker potrebovali prevajalnik C. Žal so prevajalniki C veliki programi. Ker načrtujemo povečanje in zmanjšanje števila zabojnikov glede na povpraševanje po opravljenih storitvah, bi morala biti slika v idealnem primeru čim manjša.



V bistvu želimo zgraditi kodo C s prevajalnikom C in nato zavreči prevajalnik C, da prihranimo prostor v naši podobi za uvajanje.

Primeri

Naslednji primeri bi morali pojasniti problem in njegovo rešitev. Opomba: Predvidevam, da uporabljate sistem, ki ga navdihuje POSIX.



Nastaviti

Kopirajte naslednjo datoteko Makefile v trenutni delovni imenik.

.PHONY: build-break build-break: docker build -t blog-python:break -f ./Dockerfile.break . .PHONY: build-big build-big: docker build -t blog-python:big -f ./Dockerfile.big . docker images .PHONY: build-uninstall-big build-uninstall-big: docker build -t blog-python:big-uninstall -f ./Dockerfile.uninstall . docker images .PHONY: build-small build-small: docker build -t blog-python:small -f ./Dockerfile.small . docker images

Primer 1: zlomljena gradnja, ki zahteva prevajalnik C.

Imamo preprosto, Vstopna točka -brez posode Docker, v katero moramo namestiti uWSGI . V uWSGI hiter začetek vodič, njegovi razvijalci pojasnjujejo, da gre za (veliko) aplikacijo C, zato potrebujete prevajalnik C (na primer gcc ali clang) in razvojne glave Python.

Kopirajte naslednjo kodo v datoteko z imenom Dockerfile.break:

FROM python:3.6-alpine as breakimage RUN pip install uwsgi

Zdaj zaženite naslednji ukaz lupine v istem imeniku kot vaš Dockerfile.break.

make build-break

Na koncu neuspele gradnje vidimo to sledenje (poleg drugih koristnih sporočil):

Traceback (most recent call last): File '', line 1, in File '/tmp/pip-install-tkd8plx9/uwsgi/setup.py', line 137, in 'Programming Language :: Python :: 3.6', File '/usr/local/lib/python3.6/site-packages/setuptools/__init__.py', line 129, in setup return distutils.core.setup(**attrs) File '/usr/local/lib/python3.6/distutils/core.py', line 148, in setup dist.run_commands() File '/usr/local/lib/python3.6/distutils/dist.py', line 955, in run_commands self.run_command(cmd) File '/usr/local/lib/python3.6/distutils/dist.py', line 974, in run_command cmd_obj.run() File '/tmp/pip-install-tkd8plx9/uwsgi/setup.py', line 77, in run conf = uc.uConf(get_profile()) File '/tmp/pip-install-tkd8plx9/uwsgi/uwsgiconfig.py', line 747, in __init__ raise Exception('you need a C compiler to build uWSGI') Exception: you need a C compiler to build uWSGI

V skladu z dokumentacijo uWSGI je naš sistem dejal, da za izdelavo uWSGI potrebujemo prevajalnik C. To bomo storili v primeru 2.

kako izgleda deaktiviran facebook račun

Primer 2: velika gradnja z nameščenim prevajalnikom C.

V tem primeru bomo namestili naše sistemske odvisnosti, tako da bo uWSGI dejansko mogoče zgraditi.

Kopirajte naslednjo kodo v datoteko z imenom Dockerfile.big:

FROM python:3.6-alpine as bigimage RUN apk add --no-cache linux-headers g++ RUN pip install uwsgi

Zdaj zaženite naslednji ukaz lupine:

make build-big

V cilj make-build-big sem vključil ukaz za seznam vseh slik Dockerja v vašem sistemu. Zaradi tega ukaza bi morali v svojem terminalu videti nekaj podobnega temu:

REPOSITORY TAG IMAGE ID CREATED SIZE blog-python big 8a68d0dad407 Less than a second ago 251MB python 3.6-alpine 8eb1c554687d 16 hours ago 90.4MB

Dobro

Slika je bila uspešno zgrajena.

napoved bitcoin za goldman sachs

Slabo

Slika je po nepotrebnem velika.

Načrtujemo, da bomo naše spletne storitve povečali za dostojno količino prometa. Skaliranje bo vključevalo uvajanje številnih slik na številne strežnike. Večje slike trajajo dlje časa za namestitev in (očitno) zavzamejo več prostora kot manjše slike.

Grda

Vključujemo nepotrebno odvisnost.

Na sliki ne potrebujemo prevajalnika C, zato je prevajalnik C nepotrebna odvisnost. Vključitev nepotrebne odvisnosti v našo sliko v času izvajanja je grozljiva zasnova, podobna vključitvi nepotrebne odvisnosti Pythona v naše zahteve.txt ali setup.py . Kot veliki razvijalci programske opreme sovražimo slabo zasnovo sistema, zato poiščimo način, kako razrešiti slabo in grdo, hkrati pa ohraniti dobro!

Primer 3: neuspešen poskus preproste odstranitve prevajalnika C.

Na žalost, če želimo zmanjšati velikost slike, ne moremo preprosto odstraniti prevajalnika C. Zaradi razlogov, ki jih trenutno ne razumem v celoti, Docker predpomni vse, kar namestite v sliko, zato odstranitev odvisnosti NE zmanjša velikosti slike.

Kopirajte naslednjo kodo v datoteko z imenom Dockerfile.uninstall:

FROM python:3.6-alpine as bigimage-uninstalled RUN apk add --no-cache linux-headers g++ RUN pip install uwsgi RUN apk del linux-headers g++

Zdaj zaženite naslednji ukaz lupine:

make build-uninstall-big

V svojem terminalu bi morali videti nekaj podobnega:

REPOSITORY TAG IMAGE ID CREATED SIZE blog-python big-uninstall 10a0eb5d42aa Less than a second ago 251MB blog-python big 8a68d0dad407 11 minutes ago 251MB python 3.6-alpine 8eb1c554687d 16 hours ago 90.4MB

Naša prizadevanja za odstranitev našega prevajalnika C so se izkazala za neuspešna. Na tej točki bi manjši razvijalci obupali in domnevali, da smo prišli do konca poti. Toda vi, dragi bralec, berete moj blog in vem, da ste boljši od tega! Poglobimo se in poiščimo eleganten način, kako skrčiti našo podobo Dockerja!

oblikovanje spletne strani Abu Dhabi

Primer 4: majhna končna izdelava brez prevajalnika C.

Ta zadnji primer ima za posledico majhno sliko z nameščenim uWSGI in brez prevajalnika C. Močno se opira na večstopenjske konstrukcije in na pip kolesih.

Kopirajte naslednjo kodo v datoteko z imenom Dockerfile.small:

########################################### # Throwaway image with C compiler installed FROM python:3.6-alpine as bigimage # install the C compiler RUN apk add --no-cache linux-headers g++ # instead of installing, create a wheel RUN pip wheel --wheel-dir=/root/wheels uwsgi ########################################### # Image WITHOUT C compiler but WITH uWSGI FROM python:3.6-alpine as smallimage COPY --from=bigimage /root/wheels /root/wheels # Ignore the Python package index # and look for archives in # /root/wheels directory RUN pip install --no-index --find-links=/root/wheels uwsgi

Zdaj zaženite naslednji ukaz lupine:

make build-small

V svojem terminalu bi morali videti nekaj podobnega:

REPOSITORY TAG IMAGE ID CREATED SIZE blog-python small b952f6280b00 1 second ago 97.4MB 91c7bb911f32 3 minutes ago 249MB blog-python big-uninstall 10a0eb5d42aa 23 minutes ago 251MB blog-python big 8a68d0dad407 34 minutes ago 251MB python 3.6-alpine 8eb1c554687d 16 hours ago 90.4MB

Upoštevajte, da je majhna označena slika ~ 61% manjša od velikih. Od osnovnega alpskega zabojnika ima 7 dodatnih MB. Ti megabajti predstavljajo samo knjižnico uWSGI. Morali bomo spremeniti sam uWSGI, da bo manjši. Spremembe uWSGI prepuščam bralcu kot vajo.

Pojasnilo

Za uspeh naše zgradbe Docker sta odgovorni dve ključni točki:

  1. Zanašanje na kopiranje med stopnjami slik v večstopenjskih gradnjah Docker. To odpravi težave z predpomnjenjem z eno samo sliko

  2. Razumevanje razlike med pip install in pip wheel

Kopiranje med stopnjami gradnje Dockerja v večstopenjski gradnji

Razen če izrecno določimo a - cilj, Večstopenjske gradnje Docker bodo označile njihovo zadnjo stopnjo. Stopnje gradnje po stopnjah se lahko sklicujejo na stopnje gradnje v smeri pretoka in iz njih kopirajo vire, podobno kot je mogoče vire kopirati iz katerega koli lokalnega ali oddaljenega datotečnega sistema v tradicionalni vsebnik Docker. Zato kodo Python prevedemo v eno fazo izdelave in to prevedeno kodo kopiramo v drugo fazo izdelave. Ker kode ni treba več sestavljati, nam ni treba prevajalec C ali glave Linuxa. Kot coup de grâce končna faza naše gradnje ne temelji na nobeni sliki z nameščenim prevajalnikom C, zato se ta pristop popolnoma izogne ​​Dockerjevim predpomnilniškim zapletom.

Zahvaljujoč večstopenjskim gradnjam Docker lahko sestavimo naš paket Python in se izognemo uvajanju sistemskih odvisnosti gradnje v končni podobi.

Razlika med pip install in pip wheel

Dockerjeve večstopenjske zgradbe so kul in vse, vendar sem videl veliko člankov o njih. Pythonovo orodje za pakiranje, pip , ni dobil toliko pozornosti s strani blogerske skupnosti. Upajmo, da bo ta razdelek razjasnil eno skupno zmedo: pip install vs pip kolo .

pip install

To je ukaz, ki ga pozna večina ljudi. Na visoki ravni potrebuje paket Python, zažene svoj setup.py , prenese in namesti svoje odvisnosti in potencialno naredi veliko več. Zaženite pip install, če želite razširiti vsebino paketa in ga uporabiti, kot je nameraval avtor.

kako si ogledate zasebne Twitter račune

Dober miselni model: pip install vzame konsolidiran sveženj navodil za kodo / izdelavo in postavi vsebino in odvisnosti paketa povsod, kjer potrebujejo operacijski sistem. Ko se pip install namesti na naš računalnik, je umestitev datotek v našem datotečnem sistemu lepa hamajang , odvisno od paketa setup.py navodila.

pip kolo

To orodje večinoma uporabljajo razvijalci knjižnic, ki želijo svoje pakete distribuirati na uporabniku prijazen način. Na primer, scikitlearn , priljubljena knjižnica Python za strojno učenje, zahteva veliko sistemskih odvisnosti zgraditi. Mnogi uporabniki Pythona, zlasti znanstveniki na področju podatkov, nočejo ali ne morejo namestiti teh odvisnosti na svoje gostiteljske stroje. Ta lastnost uporabnika je privedla do nesrečnih platform, kot so Anakonda (mnenje avtorja). Na bolj zrel način bi za tiste, ki imamo nameščene ustrezne odvisnosti, postopek namestitve pogosto trajal zelo dolgo; C, FORTRAN in po možnosti druge jezike je bilo treba sestaviti, namestitev kode, napisane v teh jezikih, pa pogosto vodi do dolge pavze za kavo.

Kolesa omogočajo razvijalcem Pythona, da sestavijo paket in njegove odvisnosti v distribucijski obliki, ki cilja na običajne arhitekture operacijskih sistemov. Danes ga namesti večina uporabnikov scikitlearna z uporabo svojega kolesa , ki vzame del časa običajnega postopka gradnje.

Dober miselni model: pipovo kolo vzame paket Python, ga pripravi za namestitev na kateri koli ciljni stroj BREZ odvisnosti od gradnje in ga postavi v ENO enostavno porazdeljeno arhivsko datoteko.

Zakaj nas to briga?

Vsi paketi Python niso razdeljeni kot kolesa. Obstaja nekaj paketov, ki večinoma temeljijo na jeziku C, ki jih je težko enkrat prevesti in uporabiti na mnogih mestih. Zdi se, da je uWSGI eden od teh paketov. Za izdelavo naše končne podobe izdelamo posodo za metanje, da izdelamo kolo za uWSGI.

Zaključek

Ko gradimo Dockerjev vsebnik za aplikacijo Python, lahko namestimo pakete, ki zahtevajo sistemske odvisnosti časa gradnje, in te sistemske odvisnosti odstranimo iz naše zadnje podobe Dockerja s kombinacijo večstopenjskih zgradb Docker, pip kolesa in namestitve pip.

#python #docker