Entrypoint
Un ENTRYPOINT ha i compiti di:
- verificare la sintassi e le opzioni del CMD
- inizializzare l’ambiente
Un ENTRYPOINT è una procedura shell con la struttura:
#! /bin/sh
.....
exec “$@”
La procedura deve iniziare con lo hash-bang, nel nostro caso #! /bin/sh
L’ultima istruzione eseguita è il chain command: esegue il CMD con gli eventuali parametri.
Esempio: postgres-alpine
Directory di progetto:
mkdir -p ~/docker/ex/postgres-alpine
cd ~/docker/ex/postgres-alpine
Dockerfile;
vim Dockerfile
FROM alpine:3.1
RUN apk add --update postgresql curl
RUN curl -o /usr/local/bin/gosu \
-SL "https://github.com/tianon/gosu/releases/download/1.2/gosu-amd64"
RUN chmod +x /usr/local/bin/gosu
RUN apk del curl && rm -rf /var/cache/apk/*
RUN mkdir /docker-entrypoint-initdb.d
RUN mkdir -p /var/run/postgresql && \
chown -R postgres /var/run/postgresql
ENV LANG en_US.utf8
ENV PATH /usr/lib/postgresql/9.3/bin:$PATH
ENV PGDATA /var/lib/postgresql/data
VOLUME /var/lib/postgresql/data
COPY docker-entrypoint.sh /
RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
USER postgres
EXPOSE 5432
CMD ["postgres"]
Notare che la prima direttiva, FROM alpine:3.1
, ha un'immagine con tag.
Non vogliamo usare il tag implicito latest
ma una versione di alpine ben nota.
Con opportuna ricerca documentale in rete, abbiamo infatti scopero che alpine 3.1
ha nei suoi repository software la release postgres 9.3
, che è la specifica versione che vogliamo installare.
Nostro Entrypoint
Uno entrypoint ha il compito di preparare l’ambiente al CMD che poi viene eseguito.
E’ quasi sempre una procedura shell.
Requisiti per la preparazione di immagini:
- conoscenza di comandi amministrativi Linux nella distribuzione scelta per l’immagine di base
- Ubuntu vs Alpine
- conoscenza della programmazione shell
- conoscenza di utilities che permettano il cambiamento batch e non interattivo di files di configurazione
sed
,awk
,tr
, ecc.
vim entrypoint.sh
#!/bin/sh
chown -R postgres "$PGDATA"
# if the datadir does not exist, create it
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
# listen on all network addresses
sed -ri "s/^#(listen_addresses\s*=\s*)\S+/\1'*'/" "$PGDATA"/postgresql.conf
# acquire or set environment variables
: ${POSTGRES_USER:=postgres}
: ${POSTGRES_DB:=$POSTGRES_USER}
# if the password exists, use it with MD5
if [ "$POSTGRES_PASSWORD" ]; then
pass="PASSWORD '$POSTGRES_PASSWORD'"
authMethod=md5
# otherwise warn, then trust an access without it
else
cat >&2 <<-'EOWARN'
****************************************************
WARNING: No password has been set for the database.
****************************************************
EOWARN
pass=
authMethod=trust
fi
# prepare the rest of the environment
if [ "$POSTGRES_DB" != 'postgres' ]; then
gosu postgres postgres --single -jE <<-EOSQL
CREATE DATABASE "$POSTGRES_DB" ;
EOSQL
echo
fi
if [ "$POSTGRES_USER" = 'postgres' ]; then
op='ALTER'
else
op='CREATE'
fi
gosu postgres postgres --single -jE <<-EOSQL
$op USER "$POSTGRES_USER" WITH SUPERUSER $pass ;
EOSQL
echo
# allow anybody to connect from any IP address
{ echo; echo "host all all 0.0.0.0/0 $authMethod"; } >> "$PGDATA"/pg_hba.conf
exec gosu postgres "$@"
fi
exec "$@"
Le procedure shell, specie per entrypoint, possono essere complesse. Occorre acquisire un certo livello di esperienza di programmazione shell.
Utility gosu
L’invocazione di una procedura shell la esegue in una sottoshell, figlia di quella corrente.
- Questo non si deve fare in un Entrypoint, se si vogliono compiere cambiamenti all’ambiente che durino
- Al termine della sottoshell i cambiamenti sparirebbero
Si può usare gosu
:
gosu
esegue il suo argomento nella shell corrente, non in una sottoshell- riceve eventuali segnali inviati alla shell originale
- è un programma originalmente scritto in Go
Alpine lo ha come package nativo nelle versioni più recenti, in quelle precedenti occorre scaricarlo da https://github.com/tianon/gosu
Build e Test
Build:
docker build -t postgres-alpine .
Lancio del contenitore:
docker run --name postalp -p 5435:5432 postgres-alpine
(porta 5435 non 5432 sullo host per evitare potenziali collisioni con un postgres già installato)
Tattica di debugging:
- La prima volta non mettere l’opzione
-d
(detached)- L’output andrà su video
- Permette il debugging specie di
docker-entrypoint.sh
- Fermare con Ctrl-C e rimuovere il contenitore
- Le volte successive mettere l’opzione
-d