CodeWorlds
Powrót do kolekcji
Przewodnik17 min czytaniaZespół CodeWorlds

Modal, uruchamianie kodu na GPU bez serwerów

Modal uruchamia funkcje Pythona na GPU w chmurze. Wersja 1.5.4, licencja klienta Apache 2.0, zamknięta platforma, cennik za sekundę i koszt zimnego startu.

Modal, uruchamianie kodu na GPU bez serwerów

Modal to płatna platforma, na której funkcję Pythona oznaczasz dekoratorem, a dostawca buduje obraz kontenera, uruchamia go na wskazanym GPU i skaluje od zera. Klient w wersji 1.5.4 jest otwarty na licencji Apache 2.0, ale sama platforma jest zamknięta i nie istnieje wariant do uruchomienia na własnym sprzęcie.

Co Modal właściwie robi

Punktem wyjścia jest zwykły plik Pythona. Tworzysz w nim obiekt modal.App, opisujesz obraz kontenera przy pomocy metod klasy modal.Image, a funkcje, które mają się wykonać zdalnie, dekorujesz przez @app.function(). Po uruchomieniu polecenia modal run klient serializuje kod, wysyła go do usługi, ta buduje obraz, startuje kontener na maszynie z wybranym akceleratorem i odsyła wynik oraz strumień logów do twojego terminala.

Zestaw obiektów wystawianych przez pakiet jest dość wąski i to jest zaleta. W modal/__init__.py eksportowane są między innymi App, Image, Function, Cls, Volume, Secret, Dict, Queue, Sandbox, Tunnel, Proxy, Retries, Cron, Period oraz dekoratory enter, exit, method, batched, concurrent, fastapi_endpoint, asgi_app, wsgi_app i web_server. Cała reszta to szczegóły implementacyjne.

Typowe zastosowania są trzy. Pierwsze to wnioskowanie modeli, czyli wystawienie punktu końcowego HTTP, który ładuje wagi raz przy starcie kontenera i obsługuje żądania. Drugie to przetwarzanie wsadowe, gdzie Function.map rozrzuca tysiące wejść po setkach kontenerów naraz. Trzecie to dostrajanie i treningi, gdzie liczy się dostęp do ośmiu kart w jednej maszynie bez podpisywania rezerwacji.

Czego Modal nie robi, jest równie ważne. Nie jest bazą danych ani kolejką produkcyjną, choć ma Dict i Queue do przekazywania stanu między kontenerami. Nie jest platformą do hostowania zwykłych aplikacji webowych z długo żyjącym procesem, bo model rozliczeniowy karze bezczynność. Nie obsługuje innych języków niż Python po stronie definicji zadań, choć istnieją oznaczone jako beta pakiety klienckie dla JavaScriptu i Go.

Klient otwarty, platforma zamknięta

To rozróżnienie decyduje o tym, czy w ogóle powinieneś sięgać po Modala, więc rozpisuję je dokładnie. Sprawdzenie licencji z trzech niezależnych źródeł daje wynik spójny, co w tej kolekcji zdarza się rzadziej, niż mogłoby się wydawać.

Źródło pierwsze to plik LICENSE w repozytorium modal-labs/modal-client. Ma 176 linii i jest to pełny tekst Apache License 2.0. Źródło drugie to metadane w rejestrze PyPI: pole license_expression ma wartość Apache-2.0, a stare pole license jest puste, co odpowiada nowszemu sposobowi deklarowania licencji w metadanych Pythona. Źródło trzecie, najczęściej pomijane, to zawartość opublikowanej paczki. Koło modal-1.5.4-py3-none-any.whl waży 979 KB, zawiera 231 plików, w tym 173 pliki .py, a po rozpakowaniu zajmuje 5,3 MB. W katalogu modal-1.5.4.dist-info/licenses/ leży plik LICENSE, którego suma kontrolna SHA-256 zgadza się co do znaku z plikiem z repozytorium. Nie ma tu żadnego rozjazdu: deklaracja, repozytorium i paczka mówią to samo, a w paczce jest realny kod, a nie atrapa.

Tyle dobrych wiadomości. Apache 2.0 obejmuje wyłącznie bibliotekę kliencką, czyli warstwę, która pakuje twój kod i rozmawia z API po gRPC. Serwer, planista zadań, system budowania obrazów, magazyn wolumenów i cała infrastruktura GPU są zamknięte i płatne. Nie ma wariantu do samodzielnego hostowania, nie ma wersji społecznościowej, nie ma nawet trybu emulacji do testów bez konta. Dokumentacja rozliczeń mówi wprost, że do korzystania z Modala trzeba mieć wpisaną metodę płatności, więc konto darmowe też wymaga karty.

Skutek praktyczny jest taki, że przywiązanie do dostawcy jest pełne. Plik z @app.function(gpu="H100") i @modal.enter() nie uruchomi się nigdzie poza Modalem. Migracja nie polega na zmianie adresu URL, tylko na przepisaniu warstwy uruchomieniowej: dekoratory trzeba zamienić na Dockerfile plus manifest wdrożenia, modal.Volume na wolumen platformy docelowej albo na wiadro obiektowe, modal.Secret na sekrety docelowe, a autoskalowanie na konfigurację innego systemu. Sama logika obliczeniowa, czyli ładowanie modelu i przetwarzanie wejść, przenosi się bez zmian, bo to zwykły Python.

Da się to ryzyko ograniczyć projektowo. Trzymaj logikę domenową w modułach, które nie importują niczego z modal, a plik z dekoratorami niech będzie cienką warstwą wejścia wołającą te moduły. Wtedy przeprowadzka kosztuje jeden plik na aplikację, a nie całe repozytorium.

Sam projekt jest aktywnie rozwijany. Wydanie 1.5.4 ukazało się 12 sierpnia 2026 roku, a repozytorium publikuje codzienne wydania deweloperskie, od 1.5.5.dev2 z 15 sierpnia po 1.5.5.dev9 z 22 sierpnia. Klient wymaga Pythona w zakresie od 3.10 do 3.14 włącznie i ciągnie kilkanaście zależności, w tym grpclib, protobuf, aiohttp, click, rich, watchfiles i synchronicity.

Pierwsza aplikacja i model programowania

Instalacja i uwierzytelnienie zajmują dwa polecenia, a reszta CLI jest przewidywalna.

Code
Bash
pip install modal

# zapisuje token w ~/.modal.toml, otwiera przeglądarkę
modal setup

# jednorazowe uruchomienie lokalnego pliku w chmurze
modal run app.py

# wdrożenie pod nazwą, punkty końcowe dostają stały adres
modal deploy app.py

# tryb pracy na żywo: zmiana pliku przebudowuje kontener
modal serve app.py

# powłoka w kontenerze zbudowanym z twojego obrazu
modal shell app.py::generate

# lista wdrożonych aplikacji i działających kontenerów
modal app list
modal container list

# raport kosztów, dostępny w planach Team i Enterprise
modal billing

Najmniejsza sensowna aplikacja wygląda tak. Wszystkie nazwy pól i parametrów pochodzą z sygnatur w modal/app.pyi z wersji 1.5.4.

Code
Python
import modal

image = (
    modal.Image.debian_slim(python_version="3.12")
    .pip_install("torch==2.5.1", "transformers==4.46.3")
    .env({"HF_HUB_ENABLE_HF_TRANSFER": "1"})
)

app = modal.App(name="inference-demo", image=image, tags={"team": "ml-platform"})

@app.function(
    gpu="L40S",
    cpu=4.0,
    memory=16384,
    timeout=600,
    startup_timeout=300,
    retries=modal.Retries(max_retries=2),
    secrets=[modal.Secret.from_name("hf-token", required_keys=["HF_TOKEN"])],
)
def embed(text: str) -> list[float]:
    import torch
    assert torch.cuda.is_available()
    return [0.0]

@app.local_entrypoint()
def main():
    print(embed.remote("witaj"))

Kilka szczegółów z tego pliku warto rozumieć, zanim pierwszy rachunek zaskoczy. Parametr timeout domyślnie wynosi 300 sekund i mierzy wyłącznie czas wykonania, w zakresie od 1 sekundy do 24 godzin. Osobny startup_timeout, dodany w wersji 1.1.4, mierzy czas startu kontenera. Jeśli go nie ustawisz, timeout obejmuje oba okresy naraz, co przy dużym modelu ładowanym w @modal.enter() bywa przyczyną tajemniczych awarii tuż po wdrożeniu. Parametr cpu liczy się w rdzeniach fizycznych, gdzie jeden rdzeń odpowiada dwóm vCPU, a minimum na kontener to 0,125 rdzenia. Parametr memory podaje się w mebibajtach.

Wywołanie z komputera lokalnego robi się przez embed.remote(...), wersja asynchroniczna to embed.remote.aio(...), embed.local(...) uruchamia kod na miejscu bez wysyłania go do chmury, a embed.spawn(...) zwraca FunctionCall do odebrania później.

Obrazy, wolumeny i klasy z GPU

Do wnioskowania rzadko wystarczy sama funkcja, bo wagi modelu trzeba załadować raz, a nie przy każdym żądaniu. Od tego jest @app.cls() razem z metodami cyklu życia.

Code
Python
import modal

app = modal.App("llm-serving")
weights = modal.Volume.from_name("model-weights", create_if_missing=True)

@app.cls(
    gpu="H100:2",
    volumes={"/weights": weights},
    min_containers=0,
    max_containers=20,
    buffer_containers=2,
    scaledown_window=300,
    enable_memory_snapshot=True,
)
@modal.concurrent(max_inputs=32, target_inputs=24)
class Generator:
    model_name: str = modal.parameter(default="Qwen3-8B")

    @modal.enter(snap=True)
    def load(self):
        self.model = load_from_disk(f"/weights/{self.model_name}")

    @modal.method()
    def generate(self, prompt: str) -> str:
        return self.model(prompt)

    @modal.fastapi_endpoint(method="POST", docs=True, requires_proxy_auth=True)
    def web(self, prompt: str) -> str:
        return self.generate.local(prompt)

    @modal.exit()
    def shutdown(self):
        self.model = None

min_containers trzyma zadaną liczbę kontenerów rozgrzanych na stałe, buffer_containers utrzymuje zapas ponad bieżące obciążenie, a scaledown_window podaje w sekundach, jak długo bezczynny kontener czeka przed wygaszeniem. Te same cztery pola przyjmuje metoda Function.update_autoscaler, którą można wołać w czasie działania, na przykład przed spodziewanym szczytem ruchu. Ustawienia z metody znikają przy kolejnym wdrożeniu aplikacji i wracają wartości z dekoratora.

Dekorator @modal.concurrent pozwala jednemu kontenerowi obsługiwać wiele wejść naraz: max_inputs to twardy limit, target_inputs to próg, powyżej którego autoskaler dokłada kontenery. Dla obciążeń związanych z GPU zwykle chcesz obu wartości blisko siebie, bo przekroczenie pojemności pamięci karty kończy się błędem, a nie kolejką.

Wolumeny to trwały magazyn plików współdzielony przez kontenery. Volume.from_name przyjmuje create_if_missing, environment_name, version i create_options. Ładowanie wag z wolumenu zamiast pobierania ich z sieci przy każdym starcie jest najprostszym sposobem skrócenia rozgrzewki, bo dokumentacja Modala podaje, że dla modeli o rozmiarze dziesiątek gigabajtów skraca to boot z minut do sekund.

Przetwarzanie wsadowe idzie przez rodzinę metod map. Sygnatura Function.map przyjmuje kwargs, order_outputs, return_exceptions i wrap_returned_exceptions.

Code
Python
@app.function(cpu=1.0, memory=2048, max_containers=500)
def transcode(path: str) -> str:
    return path.replace(".wav", ".flac")

@app.local_entrypoint()
def main():
    paths = [f"/data/{i}.wav" for i in range(100_000)]
    ok, failed = 0, 0
    for result in transcode.map(
        paths,
        order_outputs=False,
        return_exceptions=True,
    ):
        if isinstance(result, Exception):
            failed += 1
        else:
            ok += 1
    print(ok, failed)

Ustawienie order_outputs=False zwraca wyniki w kolejności ukończenia zamiast wejściowej i przy długim ogonie zadań realnie skraca całkowity czas. return_exceptions=True wrzuca wyjątki do strumienia wyników zamiast przerywać całość, co przy stu tysiącach wejść jest jedynym rozsądnym trybem. Pokrewne metody to starmap, for_each i spawn_map.

Cennik policzony na konkretach

Modal rozlicza trzy zasoby osobno i wszystkie za sekundę. Stawki poniżej pochodzą ze strony cennika sprawdzonej 22 sierpnia 2026 roku. Uwaga na sposób prezentacji: w kodzie strony są wyłącznie ceny za sekundę, a przełącznik na widok godzinowy przelicza je w przeglądarce, więc poniższe kwoty godzinowe policzyłem sam, mnożąc przez 3600.

Code
Python
# stawki za sekundę ze strony modal.com/pricing, stan na 2026-08-22
GPU_PER_SEC = {
    "B300": 0.001972,           # 7.0992 USD/h
    "B200": 0.001736,           # 6.2496 USD/h
    "H200 SXM": 0.001261,       # 4.5396 USD/h
    "H100 SXM5": 0.001097,      # 3.9492 USD/h
    "RTX PRO 6000": 0.000842,   # 3.0312 USD/h
    "A100 80GB": 0.000694,      # 2.4984 USD/h
    "A100 40GB": 0.000583,      # 2.0988 USD/h
    "L40S": 0.000542,           # 1.9512 USD/h
    "A10": 0.000306,            # 1.1016 USD/h
    "L4": 0.000222,             # 0.7992 USD/h
    "T4": 0.000164,             # 0.5904 USD/h
}
CPU_PER_CORE_SEC = 0.0000131    # rdzeń fizyczny, minimum 0.125 rdzenia
MEM_PER_GIB_SEC = 0.00000222
VOLUME_PER_GIB_MONTH = 0.09     # pierwsze 1 TiB miesięcznie bez opłaty

def cost(seconds, gpu=None, cores=0.125, gib=1.0):
    g = GPU_PER_SEC[gpu] * seconds if gpu else 0.0
    return g + cores * CPU_PER_CORE_SEC * seconds + gib * MEM_PER_GIB_SEC * seconds

# godzina H100 w kontenerze z 4 rdzeniami i 16 GiB pamięci
print(cost(3600, "H100 SXM5", cores=4, gib=16))  # 4.265712

Pierwszy wniosek: cena karty nie jest ceną rachunku. Godzina H100 SXM5 to 3,9492 USD za sam akcelerator, ale kontener z czterema rdzeniami fizycznymi i 16 GiB pamięci dokłada 0,18864 USD za procesor i 0,127872 USD za pamięć, czyli razem 4,2657 USD. To około 8 procent ponad stawkę widoczną w tabeli.

Drugi wniosek dotyczy krótkich funkcji. Tysiąc wywołań funkcji trwającej 200 milisekund, na jednym rdzeniu i 1 GiB pamięci, to 200 sekund pracy procesora i pamięci, czyli 0,003064 USD. Trzy dziesiąte centa. Przy obciążeniach bez GPU rachunek za sam czas wykonania jest praktycznie nieistotny i cała decyzja kosztowa przenosi się gdzie indziej, o czym za chwilę.

Trzeci wniosek dotyczy mnożników. Wybór regionu kosztuje od 1,5 do 1,75 raza stawki bazowej, a wykonanie nieprzerywalne, czyli bez ryzyka wywłaszczenia, kosztuje 3 razy stawkę bazową. Godzina H100 z gwarancją braku wywłaszczenia to więc 11,8476 USD, a nie 3,9492 USD. Osobny cennik mają Sandboxy i Notebooki: 0,00003942 USD za rdzeń na sekundę i 0,00000667 USD za GiB na sekundę, czyli dokładnie trzykrotność stawek standardowych, przy tej samej cenie GPU.

Plany abonamentowe wyglądają następująco.

PlanAbonamentKredyt w cenieKonteneryWspółbieżność GPURetencja logów
Starter0 USD plus zużycie30 USD miesięcznie100101 dzień
Team250 USD plus zużycie100 USD miesięcznie50005030 dni
Enterpriseindywidualnyindywidualnyindywidualneindywidualnaindywidualna

Plan Starter daje do 3 miejsc w przestrzeni roboczej, 200 wdrożonych aplikacji i 5 zadań cyklicznych. Plan Team znosi limit miejsc, podnosi liczbę aplikacji do 1000, dodaje własne domeny, stały adres IP wyjściowy, wycofywanie wdrożeń do 3 wersji i budżety na poziomie środowiska. Arytmetyka planu Team jest tu istotna: 250 USD abonamentu minus 100 USD kredytu daje 150 USD kosztu stałego miesięcznie, zanim wykonasz jakiekolwiek obliczenie. To równowartość około 38 godzin H100.

Kredyt 30 USD w planie Starter przelicza się na około 7,6 godziny H100 albo około 37,5 godziny L4 albo około 50 godzin T4 miesięcznie. Po wyczerpaniu kredytu płacisz za zużycie z karty, bez twardego odcięcia, więc pętla, która przypadkiem wystartuje sto kontenerów z A100, kosztuje realne pieniądze. Zabezpieczeniem są budżety na poziomie przestrzeni roboczej i środowiska, i to jest pierwsza rzecz do ustawienia po założeniu konta.

Wolumeny kosztują 0,09 USD za GiB miesięcznie z pierwszym tebibajtem w cenie. Cache wag o rozmiarze 200 GiB jest więc darmowy, a 2 TiB kosztuje 92,16 USD miesięcznie.

Warto też przeczytać porównanie, które Modal umieszcza na stronie cennika. Zestawia tam 75 GPU przez 24 godziny po 3 USD za godzinę, co daje 5400 USD, ze średnio 50 GPU przez 24 godziny po 3,95 USD za godzinę, co daje 4740 USD. Obie sumy zgadzają się co do centa, ale porównanie zakłada, że stawka Modala jest o około 32 procent wyższa od stawki tradycyjnej chmury, a oszczędność bierze się wyłącznie z założonego spadku średniego wykorzystania z 75 do 50 kart. Przy obciążeniu równomiernym Modal wyjdzie drożej i sam dostawca tego nie ukrywa, tylko nie mówi tego wprost.

Zimny start jako pozycja w rachunku

Przy rozliczeniu sekundowym czas rozgrzewania kontenera przestaje być niedogodnością, a staje się liczbą na fakturze. Dokumentacja Modala podaje, że sam kontener bootuje się w około sekundę, ale zanim zostanie uznany za gotowy, musi wykonać kod z zakresu globalnego modułu oraz wszystkie metody oznaczone @modal.enter(). Ten etap trwa, jak pisze dostawca, od sekund do minut.

Policzmy to. Weź funkcję na H100 wykonującą się 2 sekundy, w kontenerze z 4 rdzeniami i 16 GiB, i tysiąc wywołań. Sam czas wykonania to 2000 sekund, czyli 2,194 USD za GPU, 0,1048 USD za procesor i 0,07104 USD za pamięć, razem 2,36984 USD. Dodaj teraz realistyczne 2 procent wywołań trafiających w zimny kontener, który ładuje wagi przez 40 sekund. To 20 zimnych startów po 40 sekund, czyli 800 sekund dodatkowego czasu kontenera z podpiętym GPU: 0,8776 USD za kartę, 0,04192 USD za procesor i 0,028416 USD za pamięć. Rachunek rośnie z 2,37 USD do 3,32 USD, czyli o 40 procent, przy niezmienionej liczbie obsłużonych żądań.

Ten rachunek zakłada, że czas rozgrzewania kontenera trafia na fakturę, i dostawca to potwierdza. W sekcji pytań na stronie cennika, pod pozycją „What counts as billable time?", stoi wprost, że Modal nalicza opłatę za czas ładowania aplikacji oraz za czas przetwarzania żądań. Jest tam jeszcze jedna pozycja, o której łatwo zapomnieć przy planowaniu budżetu: domyślnie kontener żyje przez 60 sekund po ostatnim żądaniu i ten czas również jest płatny, choć długość tego okna da się zmienić. Przy karcie H100 sześćdziesiąt sekund bezczynności to około 6,6 centa za każde wygaszenie, więc obciążenie rozłożone w rzadkich, pojedynczych żądaniach płaci głównie za czekanie. Dopiero po zejściu do zera kontenerów opłata się kończy. Ta sama strona cennika obiecuje w nagłówku, że „nigdy nie płacisz za bezczynne zasoby", więc dwa zdania z jednego dokumentu mówią co innego i przy budżecie trzymaj się tego z sekcji pytań, bo to ono opisuje mechanizm. Własne zużycie sprawdzisz w raportach modal billing.

Na skracanie rozgrzewki Modal daje trzy narzędzia. Wagi trzymane w modal.Volume zamiast pobierane z sieci. Migawki pamięci przez enable_memory_snapshot=True razem z @modal.enter(snap=True), które zapisują stan procesu po inicjalizacji i wznawiają go przy kolejnym starcie. Oraz min_containers i buffer_containers, czyli po prostu płacenie za gotowość.

Ta trzecia opcja ma cenę, którą łatwo policzyć i która często rozstrzyga sprawę. Jeden kontener H100 utrzymywany przez całą dobę kosztuje 94,78 USD dziennie, czyli około 2843 USD miesięcznie, zanim obsłuży pierwsze żądanie. Jeżeli twój ruch jest na tyle równomierny, że i tak musisz trzymać kartę rozgrzaną non stop, to model rozliczeniowy Modala pracuje przeciwko tobie i sensowniej jest wynająć maszynę na godziny i postawić na niej vLLM.

Modal a alternatywy

NarzędzieSposób uruchomieniaWariant u siebieRozliczenieKiedy wybrać zamiast Modala
Modaldekoratory w kodzie Pythonanieza sekundę CPU, pamięci i GPU osobnoobciążenia skokowe z GPU
vLLM na własnej maszynieserwer HTTP, który sam utrzymujesztak, kod otwartykoszt maszyny niezależnie od ruchustałe, wysokie obciążenie
Ollama lokalniebinarka na twoim sprzęcietak, kod otwartybrak opłat poza sprzętemprototypy i praca offline
Hugging Face Inference Endpointswskazujesz model z Hubnieza czas działania instancjigotowe modele bez własnego kodu
E2Bsandbox dla kodu agentówtak, kod otwartyza czas życia sandboxuuruchamianie niezaufanego kodu
Railway i Fly.iokontener z Dockerfilenieza przydzielone zasobyzwykłe usługi HTTP bez GPU

Podział jest dość ostry. Jeżeli twoje obciążenie jest skokowe, wymaga GPU i przez większość doby nie robi nic, Modal wygrywa, bo skalowanie do zera jest tu domyślne, a nie dopisane. Jeżeli obciążenie jest równomierne, taniej wyjdzie własna maszyna z vLLM. Jeżeli w ogóle nie potrzebujesz GPU, Modal jest niepotrzebnie egzotycznym wyborem i zwykły kontener na Railway albo Fly.io będzie prostszy w utrzymaniu i łatwiejszy do przeniesienia.

W tej tabeli brakuje jeszcze jednego podejścia. Replicate też uruchamia modele na cudzych kartach, ale zamiast pisać kod z dekoratorami wybierasz gotowy model z katalogu, a wgranie własnego przechodzi przez narzędzie Cog budujące zwykły obraz kontenera. Różnica najważniejsza dla rachunku jest inna: część modeli publicznych rozlicza się nie za sekundę pracy karty, tylko za jednostkę wyjścia, czyli za obraz albo za tysiąc tokenów, więc przy tym samym zadaniu oba serwisy potrafią dać zupełnie inne kwoty. Dwie wady po tamtej stronie: biblioteka kliencka dla Pythona nie dostała stabilnego wydania od maja 2025 roku, a dokumentacja rozliczeń w jednym akapicie zaprzecza sama sobie w sprawie tego, czy nieudany przebieg jest płatny.

Typowe błędy

Pierwszy błąd to mylenie timeout ze startup_timeout. Domyślne 300 sekund obejmuje oba okresy naraz, jeśli drugiego nie ustawisz jawnie, więc model ładujący się 6 minut przerwie działanie, zanim obsłuży pierwsze żądanie, i zrobi to w sposób wyglądający na losowy.

Drugi to import ciężkich bibliotek w zakresie globalnym pliku uruchamianego lokalnie. Klient wykonuje ten plik na twoim komputerze, żeby zbudować graf aplikacji, więc import torch na górze pliku spowolni każde modal run i wymusi lokalną instalację zależności, których lokalnie nie potrzebujesz. Ciężkie importy należą do wnętrza funkcji albo do bloku image.imports().

Trzeci to min_containers ustawione „na wszelki wypadek". Każdy rozgrzany kontener z GPU kosztuje pełną stawkę przez cały czas życia. Zanim wpiszesz tam jedynkę, policz miesięczny koszt gotowości i porównaj go z kosztem opóźnienia, które chcesz usunąć.

Czwarty to pomijanie parametru cpu i memory przy zadaniach GPU. Domyślne minimum to 0,125 rdzenia fizycznego, co dla potoku, który dekoduje obrazy albo tokenizuje tekst przed wejściem na kartę, oznacza wąskie gardło po stronie procesora i kartę czekającą bezczynnie na pełnej stawce.

Piąty to używanie Sandboxów tam, gdzie wystarczy zwykła funkcja. Stawki procesora i pamięci są tam trzykrotnie wyższe, a Sandbox ma sens wtedy, kiedy naprawdę uruchamiasz kod, którego nie kontrolujesz.

Szósty to brak budżetu. Konto wymaga karty, po wyczerpaniu kredytu nie ma odcięcia, a błąd w pętli map potrafi rozpędzić setki kontenerów w kilkanaście sekund. Budżet na poziomie przestrzeni roboczej i środowiska ustawia się raz i nie ma powodu tego odkładać.

Siódmy to trzymanie logiki domenowej w tym samym pliku co dekoratory. To nie jest błąd techniczny, tylko dług, który zapłacisz w dniu, w którym Modal podniesie ceny albo zmieni warunki.

FAQ

Czy Modal można uruchomić na własnym sprzęcie?

Nie. Na Apache 2.0 udostępniony jest wyłącznie klient, czyli pakiet modal z PyPI. Serwer, planista, system budowania obrazów i infrastruktura GPU są zamknięte. Nie ma wersji społecznościowej ani trybu offline do testów.

Ile realnie kosztuje godzina H100?

Sam akcelerator to 3,9492 USD za godzinę, licząc ze stawki 0,001097 USD za sekundę. Do tego dochodzi procesor i pamięć kontenera, więc typowa konfiguracja z 4 rdzeniami i 16 GiB daje 4,2657 USD za godzinę. Wykonanie nieprzerywalne mnoży to przez trzy, a wybór regionu przez 1,5 do 1,75.

Co dokładnie zawiera plan darmowy?

Plan Starter kosztuje 0 USD abonamentu i zawiera 30 USD kredytu na obliczenia miesięcznie, do 3 miejsc w przestrzeni roboczej, 100 kontenerów, współbieżność 10 GPU, 200 wdrożonych aplikacji, 5 zadań cyklicznych i 1 dzień retencji logów. Karta płatnicza jest wymagana mimo zerowego abonamentu.

Czy zimny start jest naprawdę problemem?

Zależy od modelu. Kontener bootuje się w około sekundę, ale kod z zakresu globalnego i metody @modal.enter() potrafią zająć minuty przy dużych wagach. Przy rozliczeniu sekundowym to widać na rachunku, a nie tylko w opóźnieniu. Wagi na wolumenie i migawki pamięci skracają ten czas najbardziej.

Jak trudno przenieść aplikację z Modala gdzie indziej?

Logika obliczeniowa przenosi się bez zmian, bo to zwykły Python. Przepisać trzeba całą warstwę uruchomieniową: dekoratory na Dockerfile i manifest, wolumeny na magazyn docelowy, sekrety, autoskalowanie i punkty końcowe. Trzymanie tej warstwy w osobnym, cienkim pliku ogranicza koszt do jednego pliku na aplikację.

Czy Modal nadaje się do zwykłej aplikacji webowej?

Rzadko. Dekoratory @modal.fastapi_endpoint i @modal.asgi_app działają poprawnie, ale model rozliczeniowy i skalowanie od zera są zaprojektowane pod obliczenia, a nie pod długo żyjący proces obsługujący ruch przez całą dobę. Do takich zastosowań prostszy będzie kontener na zwykłej platformie hostingowej.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie