Minden eddigi megközelítésünk lényege az egyszerűség volt, hogy kis lépésekben haladjunk előre. Eljött az a pont, amikor már elhagyjuk a kényelmes hoszt network-öt és a konténerek saját IP-t kapnak. Ezzel viszont bonyolódik a több weboldal elérése, amennyiben minden weboldalt külön konténerben indítunk. Bár a HTTPD-vel is konfiguráltunk proxy-t, jellemzően nem azt használjuk erre a célra, hanem például NginX-et vagy HAProxy-t. A következőkben az NginX proxy konfigurálását mutatom be dinamikusan generált konfigurációs fájllal, hiszen nem tudjuk előre a konténerek IP címeit, ráadásul meg is változhatnak időnként. Innentől kezdve minden konténert, beleértve az előző alkalmakkor konfigurált fájlfeltöltőt és letöltőt, illetve alapértelmezett weboldalt is ugyanazon a proxy-n keresztül fogjuk elérni. Bár élesben a fájlfeltöltő mögötti PHP sem a parancssori PHP-ból indított webszerverrel fog működni, ezt most hagyjuk, ahogy van és csak a proxy-ra koncentrálunk.
Tartalomjegyzék
- Mappastruktúra átalakítása
- Proxy projekt
- Alapértelmezett weblap
- Letöltő szolgáltatás
- Fájlfeltöltés
- Fileshare docker-compose.yml
- Végszó
Mappastruktúra átalakítás
[Tartalom]
Mivel virtuális hosztokkal kezdtük, a projekt neve is az volt, ami egyelőre marad, de a Python virtuális környezet nevét én leegyszerűsítem, hogy "venv" legyen a név a promptban és a shellben is egyszerűbben lehet hivatkozni rá aktiváláskor. Mielőtt bármit csinálok, előbb törlöm a jelenlegi konténereket a compose projektben, amíg még megvan a jelenlegi konfigurációs fájl, ezután ugyanis más lesz a projekt neve is.
Ha elfelejtettem volna, akkor is tundám törölni a konténereket, network-öket és volume-okat a "docker" paranccsal, hiszen a Docker Compose csak egy segédprogram, ami YAML konfigurációs fájlt biztosít.
Törlöm a "httpd-vhosts-env" mappát és újratelepítem a Docker Compose-t is. Mindezt a sorozat első részében, a Docker Compose használatánál már bemutattam, de az új névvel az aktuális parancsok a következők:
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install docker-compose==1.28.5
Az új mappanév miatt a .gitignore-ban és a .dockerignore-ban is át kell írni a "httpd-vhosts-env"-et "venv"-re.
Mivel most nem csak több Docker image-ünk lesz, hanem több Docker Compose projektünk is, az eddigi projekt fájljai eggyel mélyebb mappaszintre kerülnek, a többi projektet pedig mellettük hozzuk majd létre:
mv httpd fileshare/
mv uploader fileshare/
mv docker-compose.yml fileshare/
Több YAML fájlt fogunk szerkeszteni, ezért egy .editorconfig fájllal érdemes lehet beállítani a preferált indentálás és a sortörés stílusát. Ezt persze támogatnia kell a használt kódszerkesztő programnak is, de ma már általában ez nem probléma. Ez a lépés opcionális, hiszen, a YAML számára szükséges space-ek enélkül is beírhatók, a behúzás értéke (indent_size
) pedig más is lehet, de enélkül nekem nem volt teljesen következetes, hogy éppen milyen behúzásokat használ a Visual Studio Code.
[*]
end_of_line = lf
indent_size = 2
indent_style = space
Proxy projekt
[Tartalom]
A proxy egy külön Docker Compose projekt lesz, ezért külön mappát kap a fileshare mappa mellett.
cd proxy
A proxy-hoz nem készítünk saját image-et, hanem egy létezőt fogunk használni Jason Wildertől. Kétféle image-e van:
- jwilder/nginx-proxy: Tartalmazza az NginX szervert és a "docker-gen" komponenst, ami Go template-ből generálja az NginX számára a konfigurációs fájlt.
- jwilder/docker-gen: Kizárólag a "docker-gen" komponenst tartalmazza, ezért bár hosszú távon hasznos lehet szétválasztani az NginX-et a konfigurációs fájlt generáló konténertől, ennek konfigurációja komplikáltabb.
Az egyszerűbb megoldásnál maradva egyelőre az "nginx-proxy" image-et használjuk aminek a működési elve a következő:
- Az NginX a
/etc/nginx/conf.d/default.conf
konfigurációs fájl alapján fogja irányítani a kéréseket. - A
default.conf
-ot a docker-gen fogja generálni. - A generáláshoz a
/etc/docker-gen/templates/nginx.tmpl
sablonfájlt fogja használni. - A sablonfájl olyan adatokra támaszkodik, amit a docker-gen a Docker API-tól fog elkérni. Ezek az adatok például a konténer IP címe, a kért domain név és hogy milyen hálózatoknak a része, mert csak azonos Docker hálózatból érik el egymást a konténerek közvetlenül.
- A konfigurációs fájl legenerálása után a docker-gen értesíti az NginX-et, hogy újra kell tölteni a konfigurációs fájlt.
- Az NginX a
default.conf
alapján a kívülről beérkező HTTP kéréseket a tetszőleges porton futó szolgáltatások felé irányítja a konténerekben, miközben az NginX végig a 80-as porton érhető el, vagy a 443-as porton is HTTPS protokoll esetén.
Ahhoz, hogy a proxy és a többi konténer lássák egymást, azonos network-ön kell lenniük. Mivel alapértelmezetten minden Docker Compose projekt kap saját hálózatot, a proxy-nál ezt felülírjuk és egy külső Docker network-re csatlakozunk, amit előbb létre kell hozni a docker paranccsal:
A hálózat külső neve "proxy-web" lesz, hogy meg tudjuk különböztetni a compose fájlban a hivatkozható belső nevétől, ami "proxy" lesz és az alábbi módon konfiguráljuk közvetlenül a proxy mappában levő "docker-compose.yml
" fájlban a compose fájl verzió megadása után.
networks:
proxy:
external: true
name: proxy-web
A proxy-t ki is kell engedni a 80-as porton a külvilág felé, de mivel már nem a hoszt hálózatán indítjuk a konténert, ezért kell egy port átirányítás.
nginx-proxy:
image: jwilder/nginx-proxy:0.9.0
ports:
- "80:80"
Az első port szám a külső port, a második a ketttőspont után a konténernek a portja. Esetünben mindkettő 80-as, de a külső portot tetszőlegesen meg lehet változtatni. A "docker-gen"-nek el kell tudnia érni a Docker API-t, ezért felcsatoljuk a Docker socket fájlt bind mounttal a "ports" kulcsszóval egy oszlopban az "nginx-proxy" service alatt:
- type: bind
source: /var/run/docker.sock
target: /tmp/docker.sock
A httpd-vhosts.conf
-ban elsőként definiált virtuális hoszt szerepét alapértelmezett hosztként egy külön konténer fogja felváltani, amihez tartozó domain nevet a DEFAULT_HOST
környezeti változóban kell megadnunk. Ez a környezeti változó a konténerbe belépve akár a bash-ből is elérhető, de a "docker-gen" is ezt fogja felhasználni. Ennek a domainnek nem kell kívülről elérhetőnek lennie, így a neve lehet egyszerűen csak "default", ha a konténernek más célja nincs.
DEFAULT_HOST: default
Mivel az NginX Proxy konténerben két névtelen volume is létrejön, azért, hogy a projekt törlése és újra létrehozása közben ne szemeteljük tele az amúgy nem is használt volume-okkal a volume listát, nevesített volume-ként definiáljuk a network definíció és a services kulcsó között:
nginx-dhparam:
nginx-certs:
Ezt viszont fel is kell catolni a "volumes" blokk alatt, ahol a docker socket-et is felcsatoltuk:
- type: volume
source: nginx-dhparam
target: /etc/nginx/dhparam
- type: volume
source: nginx-certs
target: /etc/nginx/certs
A teljes docker-compose.yml
a következő lesz ezután:
networks:
default:
external: true
name: proxy-web
volumes:
nginx-dhparam:
nginx-certs:
services:
nginx-proxy:
image: jwilder/nginx-proxy:0.9.0
ports:
- "80:80"
volumes:
- type: bind
source: /var/run/docker.sock
target: /tmp/docker.sock
- type: volume
source: nginx-dhparam
target: /etc/nginx/dhparam
- type: volume
source: nginx-certs
target: /etc/nginx/certs
environment:
DEFAULT_HOST: default
Ezután lehet indítani a projektet:
A proxy ugyan elindul, de még egy hibaoldal fog megjelenni, mivel egyetlen konténer sincs, amire irányíthatná a kérést, még a default konténer sem készült el.
Alapértelmezett weblap
[Tartalom]
Az alapértelmezett weblap egy külön projekt lesz a "fileshare" és a "proxy" mellett. Először is "default" mappanévvel hozzuk létre:
mkdir default
cd default
Ehhez az index.html
tartalma legyen a következő:
Az egyszerű Dockerfile
-ban mindőssze ennek a HTML-nek a felmásolása lesz:
COPY index.html /usr/local/apache2/htdocs/index.html
A gyökérkönyvtár most már viszont a /usr/local/apache2/htdocs
lesz, ami az alapértelmezett gyükérkönyvtár a HTTPD-nél. Mivel a HTTPD virtuális hosztban sem konfiguráltunk mást, most itt is megelégszünk ennyivel. A dockr-compose.yml
nem sok újdonságot tartalmaz majd. Minden compose projektben meg kell adni a proxy-hoz tartozó Docker hálózatot. Bemásolhatnánk ugyanazt is, mint amit a proxy-nál megadtunk, viszont itt egy másik megoldást alkalmazunk. Ahelyett, hogy az alapértelmezett hálózatát módosítanánk a compose projektnek, egy új néven hivatkozunk a "proxy-web" külső hálózatra. Itt elég lesz a "default" helyett csak a "proxy"-t írni a proxy projektben konfiguráltakhoz képest.
proxy:
external: true
name: proxy-web
Ilyenkor viszont a service-nél közvetlenül a "services" blokkban definiált "httpd" nevű service blokkjába a már ismerős "build"-del egy oszlopban felsoroljuk a service által elérhető hálózatokat. Jelenleg azt az egyet.
- proxy
Ezután pedig ugyanebben az oszlopban a VIRTUAL_HOST
nevű változóban adjuk meg, hogy a konténerhez milyen domain nevet rendelünk.
VIRTUAL_HOST: default
A teljes compose fájl a következő:
networks:
proxy:
external: true
name: proxy-web
services:
httpd:
build:
context: .
dockerfile: Dockerfile
environment:
VIRTUAL_HOST: default
networks:
- proxy
Most a szokásos paranccsal elindítjuk az alapértelmezett szolgáltatást:
Most már a 127.0.0.1
IP címen az "Unknown site" felirat lesz, de mivel még semmilyen másik servicünk nem fut, ezért mindenképpen ezt látnánk.
Letöltő szolgáltatás
[Tartalom]
A letöltő szintén külön projekt lesz, de csak egy kicsivel lesz bonyolultabb a default szolgáltatásnál. Ehhez a fileshare mappában most egy "downloads" mappát kell létrehozni, a "httpd" mappa pedig már csak referenciaként lesz használva, a Docker Compose-nak már nem lesz rá szüksége.
mkdir fileshare/downloads
cd fileshare
Az index fájlt másolhatjuk a httpd mappából:
De emlékeztetőül a tartalma a következő
<a href="files">Downloads</a>
</p>
A Dockerfile-ban most egy új utasítást is használunk. Ez pedig a RUN
, amivel shell parancsokat írhatunk. Ezeket majd &&
karakterekkel fűzzük össze, így, ha bármelyik utasítás hibával tér vissza, leáll az image készítés. Ha ez egy bash szkript lenne, akkor az alábbi sorokat írnánk ahhoz, hogy Az awk-val a ServerAdmin direktíva értékét megváltoztassuk a httpd.conf
fájlban ahelyett, hogy az egész fájlt kimásolnánk az image-ből és csak az egy sor módosítása miatt visszatöltenénk.
&& awk '\
{\
gsub("ServerAdmin you@example.com", "ServerAdmin webmaster@127.0.0.1.nip.io");\
print $0\
}\
' conf/httpd.conf.orig > conf/httpd.conf \
&& unlink conf/httpd.conf.orig
A Dockerfile-ban pedig hasonló lesz, csak a RUN kulcsszó után.
RUN mv conf/httpd.conf conf/httpd.conf.orig \
&& awk '\
{\
gsub("ServerAdmin you@example.com", "ServerAdmin webmaster@127.0.0.1.nip.io");\
print $0\
}\
' conf/httpd.conf.orig > conf/httpd.conf \
&& unlink conf/httpd.conf.orig
COPY index.html /usr/local/apache2/htdocs/index.html
Akár már indíthatnánk is a HTTPD-t, de a feltöltőben is kell még egy apróságot változtatni előbb.
Fájlfeltöltő
[Tartalom]
Egy konténeren belül futó webes szolgáltatást a konténer IP címét megadva is el lehet érni akár a hosztról, akár az azonos Docker hálózatban levő konténerekből. Így dolgozik a proxy szerver is, de meg kell neki adni azt az infót is, hogy milyen porton fut a szolgáltatás a konténerben. Ezt lehetne akár a Docker Compose fájlban is, de a Dockerfile-ba is beírható, hiszen az image készítője a saját image-ében definiált portokat ismeri. A fileshare/uploader/Dockerfile
végére tehát bekerül a következő:
Bár az NginX szervernek a 80-as portját érjük el, a konténer 8080-as portján fut a PHP CLI szerver. A teljes Dockerfile tehát:
COPY index.php /var/www/index.php
CMD [ "php", "-S", "0.0.0.0:8080", "-t", "/var/www" ]
EXPOSE 8080
Fileshare docker-compose.yml
[Tartalom]
Az image-ek leíró fájljai már készen vannak, viszont a "fileshare" projektben a docker-compose.yml
is aktualizálásra szorul.
- Először is a "httpd" nevű service most konkrétabban "downloads" lesz, aminek megfelelően a "context" értéke is megváltozik.
- A "
network_mode: host
" helyett most a "default" projekthez hasonlóan itt is az external proxy hálózatra kell hivatkozni. - Megadjuk szintén a környezeti változóban a domain nevet, ami eddig a virtuális hoszt definiícióban volt.
- A változó gyökérkönyvtár miatt a downloads szolgáltatásban a "files" volume felcsatolásánál a "target" könyvtár is változik
/usr/local/apache2/htdocs/files
-ra
Az egyenkénti kódsorok helyett most már gyakorlottabban nézhetjük egyben a teljes docker-compose.yml
fájlt a fileshare mappában:
volumes:
files:
networks:
proxy:
external: true
name: proxy-web
services:
downloads:
build:
context: downloads
dockerfile: Dockerfile
volumes:
- type: volume
source: files
target: /usr/local/apache2/htdocs/files
read_only: true
environment:
VIRTUAL_HOST: downloads.127.0.0.1.nip.io
networks:
- proxy
uploader:
build:
context: uploader
dockerfile: Dockerfile
volumes:
- type: volume
source: files
target: /var/www/files
environment:
VIRTUAL_HOST: 127.0.0.1.nip.io
networks:
- proxy
És igen, nincs más hátra, mint el is indítani a projektet:
Végszó
[Tartalom]
Most már minden oldalunk a proxy-n keresztül érhető el. A konténerben tetszőleges porton futhatnak a szolgáltatások, aminek az értékét az "EXPOSE" metaadat definiálásával adjuk meg az NginX számára. A felhasználók szemszögéből ez ugyanúgy fog működni, mint a virtuális hosztok működtek, de már egymástól teljesen függetlenül tudjuk az egyes szolgáltatásokat frissíteni, illetve a HTTPD helyett tetszőleges szerver programokat használhatunk.
Igen, ezzel viszont egy újabb szoftvert kell karban tartanunk, mivel az NginX-en megy keresztül minden forgalom, annak konfigurációja is befolyásolja az alkalmazásaink működését, ezért az NginX konfigurációjával is tisztában kell lennünk. Adott esetben módosíthatjuk az alapértelmezett template-et, vagy fel is csatolhatunk további konfigurációs fájlokat egy adott hosztra vonatkozóan, vagy a teljes nginx-re érvényeset. Ennek mikéntjéről a Docker Hub-on is lehet olvasni.
Ha tetszett a cikk, lepj meg egy like-kal. Kérés vagy kérdés esetén pedig fordulj hozzám bizalommal. A hozzászólásaiddal te is alakíthatod az IT sziget tartalmait.