--- name: ci-container-build description: | Creating or modifying CI container build workflows. Activates when consumer needs to build a custom CI container image (multi-tool image for tests, linting, validation) that is pushed to a container registry for use in other pipeline jobs. activation-gate: | User mentions CI container, custom CI image, ci-container-build, Dockerfile for CI tools, multi-tool container, or needs to build/push a container that other CI jobs will use as their runtime environment. category: ci impact: high --- # CI Container Build — Template Template jolla consumer luo oman CI-kontin build-workflown. Kontti sisältää useamman työkalun yhdistelmän (esim. helm + kubeconform + xsltproc), jota muut jobit käyttävät ajonaikaisena ympäristönä. ## Rakenne Vain `workflow_dispatch` — **ei automaattista buildausta koskaan**. Kontti buildataan manuaalisesti Gitea Actions UI:sta. Tiedoston ilmestyessä main-haaraan workflow näkyy välittömästi Actions-tabissa ajettavana. Build-prosessi lataa ensin `config-provider.yml`:llä `DOCKER_REGISTRY`:n conf-tiedostosta, sitten buildaa ja puskaa kontin. Kun kontti on pushattu registryyn, se on muiden pipeline-jobien käytettävissä `latest`-tägillä — rebuild = käyttöönotto. Mitään versioviittauksia ei tarvitse päivittää. ## Offline-periaate (DoD) CI-kontin **Definition of Done**: > Kontti ei lataa mitään pipeline-vaiheessa (`workflow run` -stepit) eikä kontin > runtime-prosessissa (`container:` / `docker run`). Kaikki riippuvuudet > (kielikohtaiset paketit, työkalut, binäärit) on joko: > - Pre-cachattu kontin **build-vaiheessa** Dockerfilessä, TAI > - Kopioitu multi-stage buildilla toisesta imagesta (`COPY --from`) > > Ainoa sallittu lataushetki on `docker build`. Sen jälkeen kontti toimii > ilman verkkoyhteyttä. **Miksi:** Toistettavuus, air gap -yhteensopivuus, nopeus. Pipeline ei saa epäonnistua sen takia että ulkoinen registry on alhaalla tai että `go mod download` joutuu latamaan 100 modulia jokaisella testiajolla. **Kielikohtaiset pre-cachet:** Jos kontissa ajetaan kielikohtaista testiä (Go, Java, Node, Python, ...), kaikki kielikohtaiset riippuvuudet on pre-cachattava Dockerfilessä build-vaiheessa: - Go: `COPY go.mod go.sum ./` → `RUN go mod download` - Java/Maven: `COPY pom.xml ./` → `RUN mvn dependency:go-offline` - Node: `COPY package.json package-lock.json ./` → `RUN npm ci --omit=dev` - Python: `COPY requirements.txt ./` → `RUN pip wheel --wheel-dir=/wheels -r requirements.txt` → `COPY --from` käyttöön ## Nimeäminen CI-kontin build-workflow noudattaa samaa nimeämiskonventiota kuin muutkin tiedostot `.gitea/workflows/`-kansiossa: ``` .ci-feature.yml ← feature-haaran reititin .ci-main.yml ← main-haaran reititin ..yml ← yksittäinen testi tai operaatio .ci-container-build-.yml ← CI-kontin build-workflow .gitea-env.conf ← komponenttikohtainen konfiguraatio ``` Single repossa `` jätetään pois — tiedostot ovat suoraan `ci-feature.yml`, `ci-main.yml`, `.yml`, `ci-container-build-.yml`. Monorepossa prefiksi pitää komponentin tiedostot yhdessä: `ls .*` löytää kaikki kerralla. **Olemassaolevia prefiksejä ei saa poistaa.** Esimerkkejä: ``` .gitea/workflows/chart.ci-container-build-helm.yml .gitea/workflows/api.ci-container-build-node.yml .gitea/workflows/ci-container-build-bats.yml ← single repo ``` ## Template > **Korvaa kaikki `__SUURAAKKOSET__`-placeholderit projektin todellisilla arvoilla.** > Ainoastaan `${{ ... }}`-syntaksilla merkityt Gitea Actions -muuttujat ovat ajonaikaisia > eikä niitä korvata. Luo `.gitea/workflows/__KOMPONENTTI__.ci-container-build-__KONTTI__.yml` (single repo: `ci-container-build-__KONTTI__.yml`): ```yaml name: CI Container Build & Push on: workflow_dispatch: inputs: config_path: required: true type: string description: 'Polku .gitea-env.conf-tiedostoon (esim. .gitea/workflows/chart.gitea-env.conf)' dockerfile_path: required: true type: string description: 'Polku Dockerfileen (esim. ci-helm.Dockerfile)' image_name: required: true type: string description: 'Kontin nimi ilman registry-polkua (esim. ci-helm)' tag: required: true type: string default: 'latest' description: 'Image-tägi' jobs: load-config: uses: __OWNER__/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 secrets: inherit with: config_path: ${{ inputs.config_path }} build-push: needs: [load-config] uses: __OWNER__/gitea-ci-library/.gitea/workflows/ci-container-build-push.yml@v1 secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} dockerfile_path: ${{ inputs.dockerfile_path }} image_name: ${{ inputs.image_name }} tag: ${{ inputs.tag }} ``` ### Käyttö **Gitea Actions UI:sta** (heti kun tiedosto on main-haarassa): ``` Gitea → Actions → CI Container Build & Push → Run workflow config_path: .gitea/workflows/__KOMPONENTTI__.gitea-env.conf dockerfile_path: ci-__TYÖKALU__.Dockerfile image_name: ci-__TYÖKALU__ tag: latest ``` ### Dockerfile Dockerfile yhdistää tarvitut työkalut yhteen konttiin. **Kaikki riippuvuudet ladataan build-vaiheessa — kontti on täysin itseriittoinen.** ```dockerfile # Tapa A: COPY --from toisesta imagesta FROM __BASE_IMAGE__:__VERSION__ COPY --from=__SOURCE_IMAGE__:__VERSION__ /path/to/binary /usr/local/bin/ RUN apk add --no-cache __PAKETIT__ # Tapa B: Build-vaiheen curl-lataus FROM __BASE_IMAGE__:__VERSION__ RUN apk add --no-cache curl __PAKETIT__ && \ curl -fsSL __URL__/__BINARY__.tar.gz | tar xz -C /usr/local/bin && \ apk del curl # Tapa C: Multi-stage + kielikohtainen pre-cache FROM __BASE_IMAGE__:__VERSION__ AS deps COPY go.mod go.sum ./ RUN go mod download FROM deps AS build COPY . . RUN go test -c -o /tmp/test.bin ./... FROM __BASE_IMAGE__:__VERSION__ COPY --from=deps /go/pkg/mod /go/pkg/mod COPY --from=build /tmp/test.bin /usr/local/bin/test ``` `COPY --from` on kevyempi (ei curl-asennusta). `curl` (Tapa B) on sallittu vain build-vaiheessa — `apk del curl` poistaa työkalun ennen runtimea. Tapa C pre-cacheaa kielikohtaiset riippuvuudet ja tuottaa täysin offline-runtime-kontin. ## Mitä EI kannata tehdä - Älä lisää `workflow_call`-triggariä — CI-konttia ei koskaan buildata automaattisesti - Älä poista `.`-prefiksiä olemassaolevista tiedostoista — ne kuuluvat monorepo-nimeämiskonventioon - Älä sisällytä CI-konttiin mitään sovelluskoodia — vain työkalut - Älä koskaan lataa mitään pipeline- tai runtime-vaiheessa — kaikki lataukset kuuluvat `docker build` -vaiheeseen (Offline-periaate) - Älä jätä kielikohtaisia riippuvuuksia pre-cachaamatta — `go mod download`, `npm install`, `mvn dependency:go-offline` jne. ajetaan Dockerfilessä, ei pipelinessä