Van egy gitea szerverünk, hozzá csatlakoztatva egy gitea runner, itt az ideje, hogy automatizáltan építsünk docker lemezképet.
Most egy picit csalni fogok, ugyanis csak a CI részről fogok beszélni, a CD külön téma, az külön cikket fog kapni.
Miről lesz ma szó?
- létrehozunk egy új git repót
- elővesszünk a korábban bemutatott Dockerfile-t
- beállítjuk, hogy használhassa a gitea runnert
- létrehozzuk a workflow-t
Mi az a workflow?
Ebben a környezetben azt a fájlt jelenti, ami leírja a teljes folyamatot.
Mit tartalmaz a workflow fájl?
3 fázisra (jobs) bontottam:
- build
- teszt
- push
A build és a push rész egyszerű, kis túlzással csak a megszokott docker build… illetve docker push… parancs lesz benne.
A teszt már jóval bonyolultabb. Igazából azért van rá szükség, hogy elkerüljük egy hibás konténer élesbe kerülését. Bár jómagam nem így csinálom. Abban nem látok kivetnivalót, hogy a test/dev/uat környezetekre automatizáltan kikerüljenek a friss konténerek, de az éles környezetre minden esetben csak alaposan kitesztelt verziót teszek fel kézzel.
A példában 5 egyszerű tesztet fogok használni, hiszen egy statikus html oldal esetén túl sok mindent nem lehet kipróbálni. A saját érdeked, hogy minél több és alkalmazás specifikus tesztet építs bele a folyamatba, mert így megúszhatsz egy csomó kézi tesztet.
A workflow-nak van még egy előnye: ha bármelyik fázis bármelyik feladata hibára fut, befejezi a futást, így elkerülve a hibás lemezkép telepítését. A workflow sikeres vagy sikertelen futása után levelet fog küldeni. Úgy készítettem el a workflow-t, hogy lehessen futtatni kézzel a gitea felületéről, fusson ütemezetten minden szombaton hajnalban, és természetesen ha a megfelelő fájlt módosítod, a git push
is be fogja indítani az automatikus build/teszt/push folyamatot!
Jöhetnek a részletek
Hozz létre egy új git repót a gitea szervereden, mondjuk cicd
néven (ezt most nem írom le, itt írtam róla).
Hozz benne létre egy build/apache-demo
nevű almappát.
Ebben a mappában hozz létre egy Dockerfile
nevű fájlt ezzel a tartalommal:
FROM alpine
ARG BUILDDATE
RUN apk add --no-cache apache2 sed \
&& addgroup -S appuser; adduser -u 12345 -G appuser -D -H appuser \
&& chown -R apache:apache /var/log/apache2 /var/www /run/apache2; chmod 777 /var/log/apache2 /run/apache2 \
&& sed -i "s/Listen 80/Listen 8080/" -i /etc/apache2/httpd.conf \
&& echo "<div style=\"text-align: center;\"><h1>Ez egy demo oldal egy apache konténerben...</h1>" > /var/www/localhost/htdocs/index.html \
&& echo "Build Date: "$BUILDDATE"</div>" >> /var/www/localhost/htdocs/index.html
USER 12345
EXPOSE 8080
WORKDIR /var/www/localhost/htdocs
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Ahogy fent említettem, ez a korábban bemutatott cikkből van kimásolva. Egy apróságon változtattam, a 9. sorban lecseréltem az appuser-t 12345-re.
Én szeretem a változókat egy külön fájlba tenni, ezért ezt is hozzuk létre a apache-demo
mappában vars.conf
néven ezzel a tartalommal:
REGISTRY="192.168.5.213:5005" # ide a saját szervered írd!
BUILD="2.4.65"
EXTPORT="8080"
INTPORT="8080"
EXTIP="172.17.0.1"
IMAGEBUILD=$REGISTRY/msandor/apache-demo:$BUILD.${hash::10} # msandor-t cseréld le a saját nevedre
IMAGELATEST=$REGISTRY/msandor/apache-demo:latest # msandor-t cseréld le a saját nevedre
CONTAINERNAME="apache-demo-test"
Most hozzuk létre a workflow fájlt a cicd git repód gyökerébe: .gitea/workflows/apache-demo.yaml az alábbi tartalommal:
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} Gitea Actions CI demo 🚀
on:
push:
paths:
- 'build/apache-demo/Dockerfile'
- 'build/apache-demo/vars.conf'
schedule:
- cron: '0 5 * * SAT' # UTC-ben értendő
workflow_dispatch:
jobs:
Build apache-demo image:
runs-on: ubuntu-24.04
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: List files in the repository
run: |
ls -lR ${{ gitea.workspace }}
- name: Build apache-demo
run: |
cd build/apache-demo
. vars.conf
hash=${{env.GITHUB_SHA}}
LCD=$(git --no-pager log -1 --format="%ai")
docker build --build-arg BUILDDATE="$LCD" --network=host --rm --progress=plain -t $IMAGEBUILD${hash::10} .
docker images | egrep "TAG|$BUILD.${hash::10}"
- name: Send email on failure
if: failure()
uses: dawidd6/action-send-mail@v6
with:
server_address: ${{ vars.SMTP_SERVER }}
server_port: 25
ignore_cert: true
subject: "Az apache-demo build sikertelen"
to: ${{ vars.SMTP_TO }}
from: ${{ vars.SMTP_FROM }}
body: "Az apache-demo build hibára futott!"
Test apache-demo image:
needs: Build apache-demo image
runs-on: ubuntu-24.04
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: 1. start apache-demo container
run: |
hash=${{env.GITHUB_SHA}}
cd build/apache-demo
. vars.conf
docker run --rm -d --name $CONTAINERNAME -p $EXTPORT:$INTPORT $IMAGEBUILD
sleep 1
docker ps -a | grep $CONTAINERNAME
- name: 2. curl header test
run: |
cd build/apache-demo
. vars.conf
curl --silent -I http://$EXTIP:$EXTPORT/
- name: 3. check apache-demo version
run: |
cd build/apache-demo
. vars.conf
docker exec $CONTAINERNAME httpd -v
curl --silent -I http://$EXTIP:$EXTPORT/ | grep "^Server: Apache"
- name: 4. check apache-demo syntax
run: |
cd build/apache-demo
. vars.conf
docker exec $CONTAINERNAME httpd -t
- name: 5. check apache-demo login page
run: |
cd build/apache-demo
. vars.conf
if [[ $(curl --silent http://$EXTIP:$EXTPORT/ | grep -c "Ez egy demo oldal egy apache") == 1 ]]; then echo test success; else exit 255; fi
- name: 6. print index.html
run: |
cd build/apache-demo
. vars.conf
curl --silent http://$EXTIP:$EXTPORT/
- name: last step, stop apache-demo container
run: |
cd build/apache-demo
. vars.conf
docker stop $CONTAINERNAME
- name: Send email on failure
if: failure()
uses: dawidd6/action-send-mail@v6
with:
server_address: ${{ vars.SMTP_SERVER }}
server_port: 25
ignore_cert: true
subject: "Az apache-demo teszt sikertelen"
to: ${{ vars.SMTP_TO }}
from: ${{ vars.SMTP_FROM }}
body: "Az apache-demo teszt hibára futott!"
Push apache-demo image to registry:
needs: Test apache-demo image
runs-on: ubuntu-24.04
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Push apache-demo image
run: |
hash=${{env.GITHUB_SHA}}
cd build/apache-demo
. vars.conf
docker tag $IMAGEBUILD $IMAGELATEST
docker push $IMAGEBUILD
docker push $IMAGELATEST
- name: Send email on success
if: success()
uses: dawidd6/action-send-mail@v6
with:
server_address: ${{ vars.SMTP_SERVER }}
server_port: 25
ignore_cert: true
subject: "Az apache-demo build sikeres"
to: ${{ vars.SMTP_TO }}
from: ${{ vars.SMTP_FROM }}
body: "Az apache-demo build sikeresen lefutott!"
- name: Send email on failure
if: failure()
uses: dawidd6/action-send-mail@v6
with:
server_address: ${{ vars.SMTP_SERVER }}
server_port: 25
ignore_cert: true
subject: "Az apache-demo push sikertelen"
to: ${{ vars.SMTP_TO }}
from: ${{ vars.SMTP_FROM }}
body: "Az apache-demo push hibára futott!"
Nézzük a fontosabb részeket soronként:
6. és 7. sor: kizárólag az itt felsorolt két fájl módosítása indítja (triggereli) be az automatikus buildelési folyamatot. Ezt minden esetben igazítsuk a saját appunkhoz. Általában a konténerbe kerülnek „kintről” fájlok, pl az src mappából, akkor vegyük fel új sorba: - 'build/apache-demo/src/*'
9. sor: ez klasszikus cron formátumban van megadva UTC szerinti időzóna szerint, azaz nyáron szombat reggel 7-kor fog lefutni, télen reggel 6-kor. Ez az oldal segít az időzítés megtervezésében. Természetesen különböző időket is be lehet állítani, tedd új sorba a 2., 3. stb időpontokat.
13. sor: az 1. fázis (job) a konténer készítés (docker build)
14., 43. és 100. sor: a gitea runner által ismert egyik (középső) konténer neve, volt ugye full, normál, és slim. A slim kevés szoftvert tartalmaz, a normál kínálata lefedte eddig minden igényem.
16. – 17. sor: az első job első lépése, ez minden jobod első lépése legyen, e-nélkül nem fog működni!
18. – 20. sor: ez pusztán „debug” funkciót lát el, kilistázza a git repó tartalmát, elhagyható, pl:

21. – 28. sor: a lényegi rész, ez készíti el a konténert 😉

29. – 39. sor: ha az 1. job valamelyik stepje hibára fut, küld el levelet. Erről még később írok bővebben.
41. sor: ez a 2. job neve
42. sor: a needs arra való, hogy sorosan indítsa a jobokat, és csak akkor lép tovább, ha az előző hibátlanul lefutott
47. – 54. sor: a teszt fázis 1. lépése, elindítja a frissen elkészült konténert. Fontos tudnivaló! Ha a teszt job bármelyik lépése megdöglik, a konténer nem fog leállni, mivel nem jutott el ahhoz a lépéshez, ami leállítja. Ilyenkor kézzel kell kilőni azon a gépen, ahol a runner fut! Ha ezt elfelejted, hiába javítod ki a yaml fájlokat, a következő futtatáskor meg fog dögleni a konténer indítása lépésnél…

55. – 59. sor: curl-al lekérem a weboldalam header-jét. Itt lehet látni, ha felesleges dolgokat is közöl a klienssel. Pl php verzió, apache verzió:

60. – 65. sor: kétféleképpen is ellenőrzöm az apache verzióját:

66. – 70. sor: mivel a konténer készítésekor belenyúltam az apache konfigurációjába (port csere 80 -> 8080), ezért jobb a békesség alapon, ellenőrzöm a szintaxisát. Hibás konfig esetén nem fog elindulni a konténer, ez segít itt kiszűrni (bár feldob egy figyelmeztetést, miszerint nincs a webszervernek FQDN-je, ettől még elindul az apache):

71. – 75. sor: ellenőrzöm, hogy a weboldalam nyitó oldalában szerepelnek-e az általam ismert (én tettem bele) szavak:

76. – 80. sor: kiíratom a nyitólapot:

81. – 85. sor: utolsó lépésként leállítom a konténert
86. – 96. sor: ha a 2. job valamelyik stepje hibára fut, küld el levelet. Erről még később írok bővebben.
98. sor: ez a 3. (és egyben utolsó) job neve
99. sor: ez is csak a teszt job sikeressége után jut szerephez
104. – 111. sor: az érdemi munka, feltölti a friss konténert azzal a tag-el, ami tartalmazza az általunk elvárt változót (a vars.conf-ból), és az utolsó git commit hash-ének utolsó 10 karakterét, valamint feltölti „latest” tag-el is:

A runner gépen így látszik:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.5.213:5005/msandor/apache-demo 2.4.65.dca5de8e28 e34e12c44763 34 minutes ago 12.3MB
192.168.5.213:5005/msandor/apache-demo latest e34e12c44763 34 minutes ago 12.3MB
112. – 122. sor: ha minden job minden lépése hibátlan volt, akkor küld egy levelet róla.
123. – 133. sor: ha a 3. job bármelyik lépése hibára futott, akkor küld egy levelet róla. Erről még később írok bővebben.
Kis segítség, hogy hogy néz ki a gitea felületén a repónk tartalma:

Mit kell tudni a levél küldésről?
Gyárilag a gitea nem küld levelet sikeres/sikertelen a CI/CD folyamatról. Természetesen látszik az összes futás kimenetele, ha megnyitod a repód Actions menüpontját:

Ha nincs szükséged levél útján értesítést kapni, akkor törölheted azokat a 10 soros blokkokat, amiket felsoroltam.
Ha hozzám hasonlóan szeretnél levelet kapni a sikeres/sikertelen CI (Continuous Integration/folyamatos integráció) eredményéről, akkor vedd fel az alábbi 3 változót:

A változók neveit tartsd meg, különben a teljes workflowban le kell őket cserélned!
Pár apróság a végére
1. Ha a docker registrydnek nincs rendes ssl certje, akkor nem fog tudni feltölteni a workflow push stepje, ilyenkor a gitea runner gépen fel kell venni a registryd IP címét/portját a /etc/docker/daemon.json
fájlba így:
{
"insecure-registries" : ["192.168.5.213:5005"]
}
2. „git push” esetén, amennyiben olyan fájlt módosítottál, ami befolyással van a konténerre (pl: Dockerfile, vars.conf), elindul az automatikus build/teszt/push folyamat. Az előre beállított időpontban is elindul a folyamat. Hogyan tudjuk kézzel elindítani? Menj a repód Actions menüpontjára, válaszd ki a kérdéses workflow yaml fájlt, és kattints a Run Workflow gombra:


3. akár több különböző konténer készítését is el lehet végezni egy git repóból, másold le a demo mappát, a hozzá tartozó workflow fájlt, szükség szerint módosítsd a mappa és fájl neveket, és írj még jobb teszt lépéseket. Nincs ebben semmi vudu 😉
Bár van teszt fázis, nézzük meg mi is a konténert
Bárhol, ahol fut a docker, és látja a registryd, add ki ezt a parancsot:
docker run --rm --name apache-demo -d -p 8080:8080 192.168.5.213:5005/msandor/apache-demo:latest
Vedd elő a kedvenc böngésződ, és nyisd meg a http://localhost:8080-as portot:

Majd állítsd le a konténert:
docker stop apache-demo
És ennyi! Végeztünk egy látszólag bonyolult feladattal. Ha valamit kihagytam volna, és nem érted a példát, nyugodtan írd le a kérdésed, megpróbálok válaszolni.
Folyt. köv. a CI/CD résszel…