ai.vostman.fi

Matkani pilven kansalaiseksi

Olin jo pitkään halunnut tehokkaan työpöytäkoneen pilveen niin, että maksaisin laskentatehosta vain käyttäessäni sitä. Halusin palata työkalujeni, projektieni ja asetusteni pariin pitämättä koko konetta käynnissä käyttökertojen välillä.

Vibe-koodaus tarjosi keinon rakentaa tällainen ympäristö ja hallita sitä. Samalla se antoi uuden syyn tarvita sitä: paikan, jossa koodausagentti voisi työskennellä oikeassa kehitysympäristössä.

Minulla oli projektille aikaa satunnaisina hetkinä, useimmiten vain puhelin käden ulottuvilla. Ympäristön piti sopia tähän tapaan työskennellä. Saatoin antaa ohjeita, tarkastaa tuloksia ja jatkaa projektia seuraavan sopivan hetken tullen.

Kokonaisuudeksi muodostui pieni jatkuvasti käytettävissä oleva kone UpCloudissa ja tarpeen mukaan käynnistettävä työpöytäkone Verdassa. Työpöytäkoneen laskentaresurssit voitiin poistaa ja levy säilyttää. Seuraava instanssi käynnistyisi samalta levyltä siihen ympäristöön, jonka olin jättänyt.

Android yhdistyy Codex-pilveen ja SSH:lla suoraan UpCloudin codex-min-koneelle. Android ja codex-min yhdistyvät verda-desktop-koneelle Tailscalen kautta. Molemmat virtuaalikoneet ajavat Codexia ja ovat yhteydessä Codex-pilveen. Codex-min hallitsee Verdaa API-rajapinnalla, ja työpöytäkone käyttää pysyvää levyä.
Artikkelin sisältö
  1. Codex pienellä jatkuvasti käytettävissä olevalla virtuaalikoneella
  2. Molempien palveluntarjoajien API-yhteydet
  3. Yhteys Androidista
  4. Pysyvä levy, vaihdettavat laskentaresurssit
  5. Saldon täydentäminen käsin ja automaattinen poistaminen

01Codex pienellä jatkuvasti käytettävissä olevalla virtuaalikoneella

Codex on pääasiallinen käyttöliittymä ympäristön rakentamiseen ja hallintaan. Se kirjoittaa asetustiedostoja ja skriptejä, suorittaa komentoja, tarkastaa tuloksia ja ottaa SSH-yhteyksiä muihin koneisiin. Lähes kaikki työ tehdään sen kautta.

Lähtökohtana oli codex-min, pieni Debian-virtuaalikone UpCloudissa. Sen palvelupaketti maksoi 3 euroa kuukaudessa ja sisälsi yhden virtuaalisen suorittimen, 1 Gt muistia ja 10 Gt levytilaa. Se ajaa Codexia ja hallintatyökaluja riippumatta Verdan suuremmasta koneesta. Codex käynnistyy koneen mukana, ja etäohjauksen kautta ympäristöön voi palata myöhemmin.

Tämä kone suorittaa agentin komennot ja säilyttää sen työtiedostot. Se ei tarvitse hallitsemansa koneen resursseja: SSH mahdollistaa komentojen suorittamisen etänä, ja palveluntarjoajien API-rajapinnat hoitavat infrastruktuurin hallinnan.

02Molempien palveluntarjoajien API-yhteydet

UpCloudin ja Verdan API-tunnuksilla hallintatyökalut voivat tarkastella resursseja sekä tehdä pyytämiäni käyttöönotto- ja elinkaaritoimia.

Näin Codex voi käsitellä ympäristön molempia tasoja. API-rajapinnan kautta se voi tarkastella instanssia tai pyytää valtuutettua infrastruktuurimuutosta. SSH:n kautta se voi määrittää käyttöjärjestelmän asetuksia ja suorittaa komentoja instanssin sisällä. Minä valitsen, milloin maksullinen laskenta käynnistetään ja mitä konetyyppiä käytetään.

Codex toimii myös verda-desktop-koneella, jossa se voi käyttää suoraan valitun instanssin resursseja.

03Yhteys Androidista

Puhelimessani ConnectBot kirjautuu SSH-avaimella ilman palvelimen käyttäjätilin salasanan syöttämistä. Julkinen avain on asennettu palvelimille, ja yksityinen avain pysyy puhelimessa. Hallintakoneella on oma SSH-avain yhteyksiin sen hallitsemille koneille.

SSH-yhteys Androidista codex-min-koneelle on suora. SSH-yhteydet sekä Androidista että codex-min-koneelta verda-desktop-koneelle kulkevat Tailscalen kautta. Näin Verdan konetta voi käyttää pysyvällä laitenimellä julkisen IP-osoitteen vaihtuessa.

SSH todentaa edelleen yhteyden. Tailscale tarjoaa verkkoyhteyden ja laitteiden osoitteet. Sen laiteidentiteetti säilyy Verdan levyllä, joten korvaava kone voi liittyä verkkoon samalla nimellä.

04Pysyvä levy, vaihdettavat laskentaresurssit

Verdan ympäristössä käyttöjärjestelmä, asennetut työkalut, projektit ja asetukset säilyvät pysyvällä järjestelmälevyllä. Laskentainstanssi voidaan poistaa levyä poistamatta. Seuraava instanssi käynnistyy olemassa olevalta levyltä.

Voin valita, millaiset laskentaresurssit liitän levyyn seuraavaa käyttökertaa varten. Edullinen CPU-vaihtoehto tarjoaa jo 4 vCPU:ta ja 16 Gt muistia. Toisessa päässä on peto: 22 vCPU:ta, 120 Gt keskusmuistia ja A100, jossa on 80 Gt GPU-muistia.

Kun virtuaalikonetta ei ole luotuna, maksan Verdassa vain tallennustilasta.

Verdan hallintakoodi ajetaan codex-min-koneella. Verdan API-yhteys käyttää asiakastunnistetta ja asiakassalaisuutta:

python
credentials = {
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
}

API on oma HTTP-asiakkaamme. Tässä on tiivistetty versio, joka käyttää Pythonin standardikirjastoa ja saa tunnukset alustajan argumenttina. Se hoitaa tokenin uusimisen, JSON-pyynnöt ja resurssiluetteloiden sivutuksen:

python
import json
import time
import urllib.request
import uuid


class API:
    def __init__(self, credentials):
        self.credentials = credentials
        self.token = None
        self.expiry = 0

    def request(self, method, endpoint, data=None, token=None):
        headers = {"Content-Type": "application/json"}
        if token:
            headers["Authorization"] = "Bearer " + token
        request = urllib.request.Request(
            "https://api.verda.com/v1" + endpoint,
            method=method,
            headers=headers,
            data=json.dumps(data).encode() if data is not None else None,
        )
        with urllib.request.urlopen(request, timeout=30) as response:
            body = response.read()
            try:
                result = json.loads(body) if body else None
            except json.JSONDecodeError:
                result = str(uuid.UUID(body.decode().strip()))
            return result, response.headers

    def call(self, method, endpoint, data=None):
        if self.token is None or time.time() >= self.expiry:
            result, _ = self.request("POST", "/oauth2/token", {
                **self.credentials,
                "grant_type": "client_credentials",
            })
            self.token = result["access_token"]
            self.expiry = time.time() + max(0, result["expires_in"] - 60)
        return self.request(method, endpoint, data, self.token)[0]

    def listing(self, endpoint):
        items = []
        page = 1
        while True:
            result = self.call("GET", f"{endpoint}?page={page}&pageSize=100")
            if not result:
                return items
            items.extend(result)
            page += 1

Luontipyynnön vastaus voi olla myös pelkkä UUID, jonka vastauksen käsittely tunnistaa. Elinkaariskripti lisää näiden operaatioiden ympärille uudelleenyritysten ja tilan hallinnan.

Seuraavaksi luodaan asiakasolio ja ladataan tallennettu elinkaaritila:

python
api = API(credentials)
state = load()

API tarjoaa konetyyppien luettelon, tämänhetkisen saatavuuden ja olemassa olevat levyt. Skripti löytää säilytetyn levyn tallennetun tunnisteen perusteella ja käyttää levyn sijaintia:

python
types = api.call("GET", "/instance-types")
availability = api.call("GET", "/instance-availability")
volumes = api.listing("/volumes")

disk = next(d for d in volumes if d["id"] == state["disk_id"])
location = disk["location"]

A100-koneen käynnistyspyynnössä valitaan 1A100.22V. CPU-vaihtoehto käyttää tyyppiä CPU.4V.16G. Olemassa olevan levyn tunniste annetaan image-kentässä, jolloin uusi instanssi käynnistyy kyseiseltä levyltä:

python
requested_kind = "1A100.22V"

plan = {
    "instance_type": requested_kind,
    "hostname": "verda-desktop",
    "description": "Persistent development desktop",
    "location_code": location,
    "image": disk["id"],
    "is_spot": False,
    "ssh_key_ids": register_keys(api, public_keys()),
}

result = api.call("POST", "/instances", plan)

Pyyntö sisältää myös rekisteröityjen SSH-avainten tunnisteet. Ennen pyynnön lähettämistä varsinainen ohjausohjelma tarkastaa kapasiteetin saatavuuden ja levyn liitostilan, ottaa automaattisen siivouksen käyttöön ja tallentaa istunnon aikarajan.

05Saldon täydentäminen käsin ja automaattinen poistaminen

Tärkein vaatimus oli, ettei huomion herpaantuminen jättäisi kallista työpöytäkonetta käyntiin määräämättömäksi ajaksi. Käyttämättömien tai liian pitkään käynnissä olleiden instanssien automaattinen poistaminen oli alusta asti välttämätöntä.

Sekä UpCloudin että Verdan kohdalla minulle oli olennaista, että pystyin valitsemaan tilin saldon täydentämisen vain käsin.

Ohjausohjelma toimii codex-min-koneella, joten se on käytettävissä myös Verdan koneen sammuttua. Se pyytää siivousta, varmistaa laskentainstanssin poistumisen ja tarkastaa levyn säilymisen. Epäonnistunutta siivousta voidaan yrittää uudelleen myöhemmällä tarkastuskerralla.

Poistopyyntö kohdistuu laskentainstanssiin ja jättää poistettavien levyjen listan tyhjäksi, jolloin järjestelmälevy säilyy:

python
api.call("PUT", "/instances", {
    "id": state["instance_id"],
    "action": "delete",
    "volume_ids": [],
})

Tavallinen käytäntö sallii kolmekymmentä minuuttia ilman vahvistettua aktiivisuutta. Ehdoton enimmäisaika on kaksitoista tuntia, ja tarkastus tehdään viiden minuutin välein. Enimmäisaika pätee, vaikka kone näyttäisi yhä aktiiviselta. Aktiivisuuden seuranta huomioi SSH-istunnot ja Codexin työn. Pelkkä käynnissä oleva Codex-taustaprosessi ei riitä aktiivisuudeksi: seuranta käyttää myös todellisten työtapahtumien aikaleimoja havaitakseen tarkastusten välillä valmistuneen työn.

Lopputuloksessa Codex ja hallintatyökalut pysyvät käytettävissä pienellä virtuaalikoneella, työympäristö säilyy levyllä ja suuremmat laskentaresurssit varataan niitä tarvitseville käyttökerroille.

Email contact