Komponiranje kontejnera alatom Docker Compose
Docker Compose (GitHub) je alat za definiranje i pokretanje višekontejnerskih aplikacija korištenjem Dockera, tzv. kompozicija (engl. composition). Usluge koje će se pokrenuti definiraju se korištenjem konfiguracije u obliku YAML. YAML je donekle srodan JSON-u, ali je dizajniran kako bi bio čitljiv ljudima (slično kao TOML).
Tip
Službeno proširenje za Docker za Visual Studio Code, između ostalog, podržava i korištenje Docker Composea.
Struktura konfiguracije
Warning
Ubuntu 20.04 LTS ima paket docker-compose koji sadrži Docker Compose verziju 1.25.0. Ta verzija podržava sve značajke koje u nastavku koristimo, ali potrebno je pripaziti da polje version
u YAML datoteci u nastavku bude postavljeno na 3.7 (umjesto 3.9) jer je verzija konfiguracije 3.8 postala dostupna tek u Docker Composeu 1.25.5, a 3.9 u 1.27.1.
Datoteka koju Docker Compose koristi ima ime docker-compose.yml
i ona može biti oblika:
version: "3.9"
services:
mojhttpd:
image: httpd
mojredis:
image: redis
U ovom slučaju pokrenut ćemo dva kontejnera, prvi naziva mojhttpd
temeljen na službenoj slici httpd, a drugi mojredis
temeljen na službenoj slici redis.
Pokretanje, nadzor i zaustavljanje kontejnera
Povucimo slike argumentom pull
(dokumentacija):
$ docker-compose pull
[+] Running 12/12
⠿ mojredis Pulled 21.1s
⠿ a2abf6c4d29d Pull complete 17.3s
⠿ c7a4e4382001 Pull complete 17.5s
⠿ 4044b9ba67c9 Pull complete 17.6s
⠿ c8388a79482f Pull complete 17.9s
⠿ 413c8bb60be2 Pull complete 18.1s
⠿ 1abfd3011519 Pull complete 18.1s
⠿ mojhttpd Pulled 21.6s
⠿ dcc4698797c8 Pull complete 17.6s
⠿ 41c22baa66ec Pull complete 17.6s
⠿ 67283bbdd4a0 Pull complete 18.5s
⠿ d982c879c57e Pull complete 18.7s
Stvaranje kontejnera na temelju preuzetih slika i njihovo pokretanje ćemo izvesti argumentom up
(dokumentacija):
$ docker-compose up
[+] Running 2/0
⠿ Container korisnik-mojhttpd-1 Created 0.0s
⠿ Container korisnik-mojredis-1 Created 0.0s
Attaching to korisnik-mojhttpd-1, korisnik-mojredis-1
korisnik-mojhttpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
korisnik-mojhttpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:26:37.086 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:26:37.086 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:26:37.086 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.087 * monotonic clock: POSIX clock_gettime
korisnik-mojhttpd-1 | [Mon Jan 03 22:26:37.087474 2022] [mpm_event:notice] [pid 1:tid 140323163139392] AH00489: Apache/2.4.51 (Unix) configured -- resuming normal operations
korisnik-mojhttpd-1 | [Mon Jan 03 22:26:37.087533 2022] [core:notice] [pid 1:tid 140323163139392] AH00094: Command line: 'httpd -D FOREGROUND'
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.087 * Running mode=standalone, port=6379.
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.087 # Server initialized
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.087 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 * Loading RDB produced by version 6.2.6
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 * RDB age 55 seconds
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 * RDB memory usage when created 0.77 Mb
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 # Done loading RDB, keys loaded: 0, keys expired: 0.
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 * DB loaded from disk: 0.000 seconds
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:26:37.088 * Ready to accept connections
Izvođenje, kao i inače, prekidamo kombinacijom tipki Ctrl+C:
^CGracefully stopping... (press Ctrl+C again to force)
[+] Running 2/2
⠿ Container korisnik-mojhttpd-1 Stopped 1.1s
⠿ Container korisnik-mojredis-1 Stopped 0.2s
canceled
Želimo li pokrenuti kompoziciju kontejnera u pozadini, dodat ćemo parametar --detach
, odnosno -d
:
$ docker-compose up -d
[+] Running 2/2
⠿ Container korisnik-mojredis-1 Started 0.3s
⠿ Container korisnik-mojhttpd-1 Started 0.3s
Argumentom ps
dobit ćemo popis pokrenutih procesa u pojedinim kontejnerima (dokumentacija):
$ docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
korisnik-mojhttpd-1 "httpd-foreground" mojhttpd running 80/tcp
korisnik-mojredis-1 "docker-entrypoint.s…" mojredis running 6379/tcp
Želimo li više informacija, primjerice koliko je točno procesa pokrenuo web poslužitelj, koliko se dugo izvode i koji su im identifikatori, ispisat ćemo ih argumentom top
, ponovno razdvojene po pojedinim kontejnerima (dokumentacija):
$ docker-compose top
korisnik-mojhttpd-1
UID PID PPID C STIME TTY TIME CMD
root 870026 869946 0 23:34 ? 00:00:00 httpd -DFOREGROUND
bin 870323 870026 0 23:34 ? 00:00:00 httpd -DFOREGROUND
bin 870324 870026 0 23:34 ? 00:00:00 httpd -DFOREGROUND
bin 870325 870026 0 23:34 ? 00:00:00 httpd -DFOREGROUND
korisnik-mojredis-1
UID PID PPID C STIME TTY TIME CMD
999 870038 869998 0 23:34 ? 00:00:00 redis-server *:6379
Argumentom logs
dobit ćemo uvid u zapisnike pojedinih kontejnera (dokumentacija):
$ docker-compose logs
korisnik-mojhttpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
korisnik-mojhttpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
korisnik-mojhttpd-1 | [Mon Jan 03 22:34:07.376872 2022] [mpm_event:notice] [pid 1:tid 140419205336384] AH00489: Apache/2.4.51 (Unix) configured -- resuming normal operations
korisnik-mojhttpd-1 | [Mon Jan 03 22:34:07.377246 2022] [core:notice] [pid 1:tid 140419205336384] AH00094: Command line: 'httpd -D FOREGROUND'
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:34:07.376 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:34:07.376 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
korisnik-mojredis-1 | 1:C 03 Jan 2022 22:34:07.376 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:34:07.376 * monotonic clock: POSIX clock_gettime
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:34:07.377 * Running mode=standalone, port=6379.
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:34:07.377 # Server initialized
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:34:07.377 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
korisnik-mojredis-1 | 1:M 03 Jan 2022 22:34:07.377 * Ready to accept connections
Zaustavljanje izvođenja izvodimo argumentom down
(dokumentacija)
$ docker-compose down
[+] Running 3/3
⠿ Container korisnik-mojhttpd-1 Removed 1.3s
⠿ Container korisnik-mojredis-1 Removed 0.3s
⠿ Network korisnik_default Removed 0.1s
Naredba podržava još argumenata, o kojima možemo saznati više proučavanjem službene dokumentacije ili korištenjem parametra --help
:
$ docker-compose --help
Usage: docker compose [OPTIONS] COMMAND
Docker Compose
Options:
--ansi string Control when to print ANSI control characters
("never"|"always"|"auto") (default "auto")
--compatibility Run compose in backward compatibility mode
--env-file string Specify an alternate environment file.
-f, --file stringArray Compose configuration files
--profile stringArray Specify a profile to enable
--project-directory string Specify an alternate working directory
(default: the path of the Compose file)
-p, --project-name string Project name
Commands:
build Build or rebuild services
convert Converts the compose file to platform's canonical format
cp Copy files/folders between a service container and the local filesystem
create Creates containers for a service.
down Stop and remove containers, networks
events Receive real time events from containers.
exec Execute a command in a running container.
images List images used by the created containers
kill Force stop service containers.
logs View output from containers
ls List running compose projects
pause Pause services
port Print the public port for a port binding.
ps List containers
pull Pull service images
push Push service images
restart Restart containers
rm Removes stopped service containers
run Run a one-off command on a service.
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker Compose version information
Run 'docker compose COMMAND --help' for more information on a command.
Korištenje izgradnje kontejnera u kompoziciji
U kompoziciji je moguće izgraditi neke od kontejnera na temelju datoteka Dockerfile
. Za ilustraciju možemo iskoristiti primjer dan u Get started with Docker Compose, web aplikaciju napisanu u Pythonu korištenjem Flaska koja dohvaća podatke iz Redisa. Datoteka app.py
je sadržaja:
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='mojredis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
Uočimo kako se povezivanje na Redis događa korištenjem imena domaćina mojredis
. To ćemo ime iskoristiti niže kao ime kontejnera.
Jasno je vidljivo iz naredbi import
da ova aplikacija za svoj rad zahtijeva Python module flask
i redis
(podsjetimo se da je modul time
dio standardne biblioteke). Stvorimo datoteku requirements.txt
koju će pip koristiti za preuzimanje potrebnih modula:
flask
redis
Stvorimo Dockerfile
koji će povući sliku kontejnera za Python, dodati u nju datoteku requirements.txt
, instalirati potrebne module (pip install -r requirements.txt
), pokrenuti aplikaciju (flask run
) i otvoriti potrebna vrata (u zadanim postavkama Flask koristi vrata 5000):
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
Ovaj kontejner bismo mogli izgraditi naredbom docker build
(dokumentacija), ali tada bismo se morali pobrinuti za Redis. Stoga ćemo napraviti docker-compose.yml
koji će izgraditi kontejner na temelju Dockerfile
-a i pokrenuti ga, izraditi i pokrenuti kontejner s Redisom pod nazivom mojredis
te povezati ta dva kontejnera mrežom:
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
mojredis:
image: "redis:alpine"
Zadatak
Promijenite kontejner tako da koristi Python 3.10 kao osnovnu sliku.
Zadatak
Promijenite korištena vrata na 8080. (Uputa: proučite dokumentaciju sučelja naredbenog retka Flaska.)
Zadatak
Po uzoru na ovu kompoziciju, složite kompoziciju koja koristi službenu sliku za php i povezuje se na Redis.
Author: Vedran Miletić