Pe lângă documentaţia oficială Docker, există câteva resurse bune pe Internet unde puteţi citi despre cum puteţi începe să lucraţi pe un mediu Docker în proiectul vostru, aici incluzând tagul Stack Overflow Docker, imaginile oficiale Docker pentru MySQL și Postgres. Din nefericire, nu sunt multe locuri unde se poate citi despre pașii ce NU trebuie urmaţi în instalarea Docker pentru o serie de studii de caz comune.
Poate vă întrebaţi "De ce ar fi cineva interesat de așa ceva?" Cred că semnificaţia acestor scenarii ţine de faptul că soluţiile se găsesc prin încercare și eșec - cam aceeași metodă aplicată de un elev de clasa a 2-a. Vă aflaţi într-o situaţie similară? Dacă da, ideile expuse mai jos vor fi utile pentru voi.
Dacă auziţi de Docker pentru prima oară, puteţi începe tutorialul, apoi să reveniţi la acest articol. Am utilizat Docker 1.12 pe macOS, în mod nativ - Docker gestionând buildul în hypervisor.
Toţi folosim baze de date. Este cel mai utilizat studiu de caz din orice serviciu distribuit, fie el mic sau mare sau din orice aplicaţie web. Dacă nu folosiţi un ORM unde entităţile să fie create "magic" de framework, atunci probabil că extrageţi date semnificative dintr-o bază de date pe care nu o deţineţi nativ. În acest caz, va trebuie să iniţializaţi datele, să creaţi baza de date și tabelele aplicaţiei.
Este important să înţelegeţi tiparul generic aplicat de MySQL sau Postgres pentru a obţine acest lucru:
Reţeta de bază va instala software-ul și orice alte utilităţi necesare, apoi aceasta va "urca" volumul de date și va lansa scriptul init (scriptul de iniţializare). Scriptul init va verifica dacă dosarul de date este gol sau nu, iar, în funcţie de starea de fapt, va lansa iniţializarea scripturilor din dosarul docker-entrypoint-initdb.d care au fost urcate/încărcate de utilizator.
Această reţetă va iniţializa baza voastră de date.
Dar ce se întâmplă în următorul caz în care folosim un container Docker în dezvoltare și emulăm baza de date reală cu cantităţi mari de date, să zicem un milion? Iniţializarea de mai sus va funcţiona, dar va dura foarte mult timp. Dacă la acest fapt mai adăugăm alte imagini într-o configuraţe Travis unde să rulaţi suita voastră de teste automate, atunci veţi avea de așteptat până containerul devine disponibil pentru o bună bucată de timp … să zicem 15 minute. Aceasta nu este o inconvenienţă în unele cazuri, dar poate fi în alte cazuri din următoarele motive:
În unul din proiectele noastre, unde trebuie să emulăm o bază de date Redshift într-o configuraţie CI/CD, am întâmpinat problemele descrise mai sus. Pentru a le evita, ne-am gândit să iniţializăm baza de date în timpul construcţiei imaginilor. Am modificat scriptul de iniţializare al bazei de date, obţinând următorul proces:
Bucata de fișier Docker ce implementează funcţionalitatea de mai sus se află mai jos:
# source: https://github.com/kiasaki/
docker-alpine-postgres
FROM alpine
RUN echo
"@edge http://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories && \
apk update && \
apk add curl "libpq@edge<9.7"
"postgresql-client@edge<9.7" "postgresql@edge<9.7"
"postgresql-contrib@edge<9.7" && \
curl -o /usr/local/bin/gosu -sSL "https://github.com/tianon/gosu/releases/download/1.2/gosu-amd64" && \
chmod +x /usr/local/bin/gosu && \
apk del curl && \
rm -rf /var/cache/apk/*
ENV LANG en_US.utf8
ENV PGDATA /var/lib/postgresql/data/
ENV POSTGRES_DB datastore
ENV POSTGRES_USER docker
ENV POSTGRES_PASSWORD letmein
RUN mkdir -p /opt/setup/data-scripts.d/
RUN mkdir -p /zdata/
COPY ./data-scripts.d/* /opt/setup/data-scripts.d/
WORKDIR /opt/setup/
COPY db-setup.sh /opt/setup/
COPY db-pack.sh /opt/setup/
COPY db-run.sh /opt/setup/
RUN ./db-setup.sh
RUN ./db-pack.sh
VOLUME $PGDATA
EXPOSE 5432
ENTRYPOINT [ "/opt/setup/db-run.sh" ]
CMD [ "postgres" ]
Din raţiuni de spaţiu, vom ignora procesele de împachetare/dezpachetare de scripturi, deși le puteţi găsi în aici. Partea care rămâne este raţionamentul produs la lansarea containerului - parte implementată în db-run.sh:
#!/bin/sh
set -e
if [ ! -f "$PGDATA/PG_VERSION" ]; then
echo "Restoring $PGDATA ..."
tar -xf /zdata/backup.tar -C $PGDATA
sync
echo "Done."
else
echo
"$PGDATA was already there, skipping restore."
fi
echo "Launching command: $@ ..."
if [ "$1" = 'postgres' ]; then
gosu postgres "$@"
else
exec "$@"
fi
În timpul procesului de bootstrap al containerului, întreaga bază de date este dezpachetată și restaurată în datele din fișerul de încărcare, iar la final, serverul este lansat printr-un mnemonic "postgres".
Rularea containerului de mai sus a optimizat construirea de imagini cu aproape 15 minute - scripturile de iniţializare au conţinut aproape 2 milioane de intrări într-o tabelă, cu doar 5 câmpuri. Partea cea mai bună este că acest container a avut nevoie doar de 2 minute pentru procesul de bootstrap din imaginea de bază. Acest fapt a îmbunătăţit experienţa utilizatorului programator care va rula procesul debug local, utilizând o bază de date, foarte apropiată de ce se găsește în producţie.
Adaptările scripturilor de iniţializare a bazei de date sunt de dificultate moderată (nefiind deloc un aspect comun), dar rezultatul final a fost fiabil. Așadar, putem recomanda această abordare oricărei persoane care se află într-o situaţie similară.