J'ai le fichier de composition Docker suivant (docker-compose-dev.yml
):
version: '3'
services:
my_sql_db:
image: percona:latest
container_name: my_sql_db
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: abhs
ports:
- "3306:3306"
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ./flyway_scripts/src/main/resources/db/migration:/flyway/sql
command: -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
depends_on:
- my_sql_db
et suivant docker-compose.yml
:
version: '3'
services:
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ./flyway_scripts/src/main/resources/db/migration:/flyway/sql
Ensuite, j'exécute la commande suivante:
docker-compose -f docker-compose.yml -f docker-compose-dev.yml up
Et cela conduit à une erreur:
Dans les journaux, je vois ce qui suit:
my_sql_db | Initializing database
flyway_migration | Flyway Community Edition 5.1.4 by Boxfuse
flyway_migration |
my_sql_db | 2018-08-24T08:47:41.616694Z 0 [Warning] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.
my_sql_db | 2018-08-24T08:47:41.616747Z 0 [Warning] 'NO_AUTO_CREATE_USER' sql mode was not set.
flyway_migration | ERROR:
flyway_migration | Unable to obtain connection from database (jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false) for user 'root': Could not connect to address=(Host=my_sql_db)(port=3306)(type=master) : Connection refused (Connection refused)
flyway_migration | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
flyway_migration | SQL State : 08
flyway_migration | Error Code : -1
flyway_migration | Message : Could not connect to address=(Host=my_sql_db)(port=3306)(type=master) : Connection refused (Connection refused)
my_sql_db | 2018-08-24T08:47:43.024690Z 0 [Warning] InnoDB: New log files created, LSN=45790
flyway_migration |
my_sql_db | 2018-08-24T08:47:43.443625Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
my_sql_db | 2018-08-24T08:47:43.588008Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 5dc59a4f-a77a-11e8-b6cb-0242ac130002.
my_sql_db | 2018-08-24T08:47:43.760654Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
my_sql_db | 2018-08-24T08:47:44.518107Z 0 [Warning] CA certificate ca.pem is self signed.
my_sql_db | 2018-08-24T08:47:44.925466Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
my_sql_db | 2018-08-24T08:47:54.762213Z 1 [Warning] 'user' entry 'root@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.762517Z 1 [Warning] 'user' entry 'mysql.session@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.762889Z 1 [Warning] 'user' entry 'mysql.sys@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.763244Z 1 [Warning] 'db' entry 'performance_schema mysql.session@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.763472Z 1 [Warning] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.763788Z 1 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.763928Z 1 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
my_sql_db | 2018-08-24T08:47:54.764128Z 1 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
my_sql_db | Database initialized
my_sql_db | MySQL init process in progress...
my_sql_db | 2018-08-24T08:47:58.970290Z 0 [Warning] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.
my_sql_db | 2018-08-24T08:47:58.970345Z 0 [Warning] 'NO_AUTO_CREATE_USER' sql mode was not set.
my_sql_db | 2018-08-24T08:47:58.974061Z 0 [Note] mysqld (mysqld 5.7.22-22) starting as process 58 ...
my_sql_db | 2018-08-24T08:47:58.999651Z 0 [Note] InnoDB: PUNCH HOLE support available
my_sql_db | 2018-08-24T08:47:58.999685Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
my_sql_db | 2018-08-24T08:47:58.999689Z 0 [Note] InnoDB: Uses event mutexes
my_sql_db | 2018-08-24T08:47:58.999692Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
my_sql_db | 2018-08-24T08:47:58.999695Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.8
my_sql_db | 2018-08-24T08:47:58.999698Z 0 [Note] InnoDB: Using Linux native AIO
my_sql_db | 2018-08-24T08:47:59.000153Z 0 [Note] InnoDB: Number of pools: 1
my_sql_db | 2018-08-24T08:47:59.000426Z 0 [Note] InnoDB: Using CPU crc32 instructions
my_sql_db | 2018-08-24T08:47:59.002306Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
my_sql_db | 2018-08-24T08:47:59.006893Z 0 [Note] InnoDB: Completed initialization of buffer pool
my_sql_db | 2018-08-24T08:47:59.013219Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
my_sql_db | 2018-08-24T08:47:59.024242Z 0 [Note] InnoDB: Crash recovery did not find the parallel doublewrite buffer at /var/lib/mysql/xb_doublewrite
my_sql_db | 2018-08-24T08:47:59.026263Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
my_sql_db | 2018-08-24T08:47:59.066469Z 0 [Note] InnoDB: Created parallel doublewrite buffer at /var/lib/mysql/xb_doublewrite, size 3932160 bytes
my_sql_db | 2018-08-24T08:47:59.071752Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
my_sql_db | 2018-08-24T08:47:59.072052Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
my_sql_db | 2018-08-24T08:47:59.422155Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
my_sql_db | 2018-08-24T08:47:59.423325Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
my_sql_db | 2018-08-24T08:47:59.423376Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
my_sql_db | 2018-08-24T08:47:59.423900Z 0 [Note] InnoDB: Waiting for purge to start
my_sql_db | 2018-08-24T08:47:59.474066Z 0 [Note] InnoDB: Percona XtraDB (http://www.percona.com) 5.7.22-22 started; log sequence number 2595255
my_sql_db | 2018-08-24T08:47:59.474647Z 0 [Note] Plugin 'FEDERATED' is disabled.
my_sql_db | 2018-08-24T08:47:59.499970Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
my_sql_db | 2018-08-24T08:47:59.500004Z 0 [Note] Skipping generation of SSL certificates as certificate files are present in data directory.
my_sql_db | 2018-08-24T08:47:59.500382Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
my_sql_db | 2018-08-24T08:47:59.501263Z 0 [Warning] CA certificate ca.pem is self signed.
my_sql_db | 2018-08-24T08:47:59.522151Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory.
my_sql_db | 2018-08-24T08:47:59.531657Z 0 [Note] InnoDB: Buffer pool(s) load completed at 180824 8:47:59
On dirait que la voie de migration commence avant l'initialisation de la base de données et n'a donc pas pu se connecter à la base de données et je vois l'erreur ci-dessous.
Comment puis-je résoudre ce problème?
J'ai googlé des questions similaires et j'ai trouvé le conseil suivant: https://github.com/vishnubob/wait-for-it mais je suis novice en docker et je ne comprends pas comment mettre dans mon fichier de composition docker
J'ai essayé de mettre le fichier wait-fot-it.sh
près du fichier de composition et exécutez:
command: ["./wait-for-it.sh", "mysql:3306", "--", "-url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate"]
Mais je renvoie ERREUR: Invalid argument: ./wait-for-it.sh
J'ai essayé l'approche du sujet "Dupliqué":
version: '3'
services:
my_sql_db:
image: percona:latest
container_name: my_sql_db
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: abhs
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ./flyway_scripts/src/main/resources/db/migration:/flyway/sql
command: -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
depends_on:
my_sql_db:
condition: service_healthy
mais je vois l'erreur suivante:
$ docker-compose -f docker-compose.yml -f docker-compose-dev.yml up
The Compose file '.\docker-compose-dev.yml' is invalid because:
services.migration.depends_on contains an invalid type, it should be an array
pour cette approche, je vois l'erreur suivante:
version: '3'
services:
my_sql_db:
image: percona:latest
container_name: my_sql_db
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: abhs
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ./flyway_scripts/src/main/resources/db/migration:/flyway/sql
command: dockerize wait jdbc:mysql://my_sql_db:3306 -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
depends_on:
- my_sql_db
Je vois l'erreur suivante:
flyway_migration | ERROR: Invalid argument: dockerize
wait-for-it.sh contenu:
#!/usr/bin/env bash
# Use this script to test if a given TCP Host/port are available
cmdname=$(basename $0)
echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$cmdname Host:port [-s] [-t timeout] [-- command args]
-h Host | --Host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the Host and port as Host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $TIMEOUT -gt 0 ]]; then
echoerr "$cmdname: waiting $TIMEOUT seconds for $Host:$PORT"
else
echoerr "$cmdname: waiting for $Host:$PORT without a timeout"
fi
start_ts=$(date +%s)
while :
do
if [[ $ISBUSY -eq 1 ]]; then
nc -z $Host $PORT
result=$?
else
(echo > /dev/tcp/$Host/$PORT) >/dev/null 2>&1
result=$?
fi
if [[ $result -eq 0 ]]; then
end_ts=$(date +%s)
echoerr "$cmdname: $Host:$PORT is available after $((end_ts - start_ts)) seconds"
break
fi
sleep 1
done
return $result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $QUIET -eq 1 ]]; then
timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --Host=$Host --port=$PORT --timeout=$TIMEOUT &
else
timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --Host=$Host --port=$PORT --timeout=$TIMEOUT &
fi
PID=$!
trap "kill -INT -$PID" INT
wait $PID
RESULT=$?
if [[ $RESULT -ne 0 ]]; then
echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $Host:$PORT"
fi
return $RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
hostport=(${1//:/ })
Host=${hostport[0]}
PORT=${hostport[1]}
shift 1
;;
--child)
CHILD=1
shift 1
;;
-q | --quiet)
QUIET=1
shift 1
;;
-s | --strict)
STRICT=1
shift 1
;;
-h)
Host="$2"
if [[ $Host == "" ]]; then break; fi
shift 2
;;
--Host=*)
Host="${1#*=}"
shift 1
;;
-p)
PORT="$2"
if [[ $PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
PORT="${1#*=}"
shift 1
;;
-t)
TIMEOUT="$2"
if [[ $TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$Host" == "" || "$PORT" == "" ]]; then
echoerr "Error: you need to provide a Host and port to test."
usage
fi
TIMEOUT=${TIMEOUT:-15}
STRICT=${STRICT:-0}
CHILD=${CHILD:-0}
QUIET=${QUIET:-0}
# check to see if timeout is from busybox?
# check to see if timeout is from busybox?
TIMEOUT_PATH=$(realpath $(which timeout))
if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
ISBUSY=1
BUSYTIMEFLAG="-t"
else
ISBUSY=0
BUSYTIMEFLAG=""
fi
if [[ $CHILD -gt 0 ]]; then
wait_for
RESULT=$?
exit $RESULT
else
if [[ $TIMEOUT -gt 0 ]]; then
wait_for_wrapper
RESULT=$?
else
wait_for
RESULT=$?
fi
fi
if [[ $CLI != "" ]]; then
if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
echoerr "$cmdname: strict mode, refusing to execute subprocess"
exit $RESULT
fi
exec "${CLI[@]}"
else
exit $RESULT
fi
J'ai aussi essayé ceci:
version: '3'
services:
my_sql_db:
image: percona:latest
container_name: my_sql_db
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: abhs
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ./flyway_scripts/src/main/resources/db/migration:/flyway/sql
entrypoint: ["wait-for-it.sh", "mysql:3306", "--", "docker-entrypoint.sh"]
command: -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
depends_on:
- my_sql_db
Cela conduit à une erreur:
Erreur lors de la création de flyway_migration ...
ERROR: for flyway_migration Cannot start service migration: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"wait-for-it.sh\": executable file not found in $PATH": unknown
ERROR: for migration Cannot start service migration: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"wait-for-it.sh\": executable file not found in $PATH": unknown
Encountered errors while bringing up the project.
Pour les erreurs:
Invalid argument: ./wait-for-it.sh
et
Invalid argument: dockerize
En effet, le point d'entrée du conteneur Flyway est l'exécutable flyway
et le contenu de la commande que vous avez spécifié est ajouté au point d'entrée en tant qu'arguments. Ainsi, en effet, le conteneur exécute les éléments suivants:
flyway dockerize ...
ou
flyway wait-for-it.sh ...
Aucun de ces arguments n'est valable pour la ligne de commande Flyway .
Le point d'entrée doit être mis à jour, comme vous l'avez fait dans P.S.5
. Cependant, vous avez ensuite rencontré l'erreur:
"wait-for-it.sh": executable file not found in $PATH"
Ceci est dû au fait wait-for-it.sh
(et dockerize
) ne sont pas disponibles dans le conteneur Flyway.
Vous pouvez soit créer un Dockerfile qui étend le conteneur Flyway puis ADD
ou COPY
les scripts, par exemple:
FROM boxfuse/flyway:latest
RUN mkdir /flyway/bin
ADD wait-for-it.sh /flyway/bin/wait-for-it.sh
RUN chmod 755 /flyway/bin/wait-for-it.sh
Ou montez un volume qui contient le script/exécutable:
version: '3'
services:
...
migration:
image: boxfuse/flyway:latest
container_name: flyway_migration
volumes:
- ../sql:/flyway/sql
- ../bin:/flyway/bin
entrypoint: ["/flyway/bin/dockerize", "-wait", "tcp://my_sql_db:3306", "-timeout", "15s", "--", "flyway"]
...
où le répertoire local ../bin
contient dockerize
(ou wait-for-it.sh).
Cela devrait être suffisant pour que dockerize/wait-for-it.sh fonctionne. Cependant, les deux outils vérifient uniquement qu'un port est disponible et non que la base de données elle-même est réellement prête à répondre aux demandes.
Cela dit, en utilisant le docker-compose v2.1 depends_on: condition
la syntaxe peut être une approche raisonnable. Comme vous l'avez mentionné dans les commentaires, cette syntaxe a été supprimée dans la v3 et beaucoup de les gens ne sont pas satisfaits .
Cependant, comme l'un des développeurs Docker le dit dans un commentaire sur ce problème :
Il n'y a aucune raison d'utiliser le format v3 si vous n'avez pas l'intention d'utiliser les services Swarm.
Une autre approche consiste à étendre le conteneur Flyway pour ajouter un script de contrôle de santé MySQL personnalisé, similaire à celui de Postgres montré dans la documentation Docker compose :
#!/bin/bash
# wait-for-mysql.sh
set -e
Host="$1"
shift
cmd="$@"
until MYSQL_PWD=$MYSQL_ROOT_PASSWORD /usr/bin/mysql --Host="$Host" --user="root" --execute "SHOW DATABASES;"; do
>&2 echo "MySQL is unavailable - sleeping"
sleep 1
done
>&2 echo "MySQL is up - executing command"
exec $cmd
Créez ensuite un Dockerfile pour étendre Flyway, installez le client MySQL et ajoutez ce script:
FROM boxfuse/flyway:latest
RUN apt-get update && \
apt-get install -y mysql-client && \
mkdir /flyway/bin
ADD wait-for-mysql.sh /flyway/bin/wait-for-mysql.sh
RUN chmod 755 /flyway/bin/wait-for-mysql.sh
Vous pouvez ensuite utiliser l'image Flyway personnalisée dans votre fichier de composition:
version: '3'
services:
my_sql_percona:
...
migration:
build: ./flyway_mysql_client
container_name: flyway_migration
environment:
MYSQL_ROOT_PASSWORD: password
volumes:
- ../sql:/flyway/sql
entrypoint: ["bash", "/flyway/bin/wait-for-mysql.sh", "my_sql_percona", "--", "flyway"]
command: -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
depends_on:
- my_sql_percona
L'inconvénient de cette approche est que vous devez étendre chaque conteneur avec un script de contrôle de santé personnalisé pour chacune de ses dépendances.
La v2.1 depends_on: condition
la syntaxe semble avoir été supprimée au profit de politiques de redémarrage dans la v3. Cependant, ceux-ci sont imbriqués dans la section deploy , qui:
prend effet uniquement lors du déploiement sur un essaim avec docker stack deploy, et est ignoré par docker-compose up et docker-compose run.
Ainsi, une autre option consiste à abandonner la composition de docker et à exécuter sur l'essaim de docker, comme suit:
Ajoutez un on-failure
politique de redémarrage du conteneur Flyway:
version: '3'
services:
my_sql_percona:
...
migration:
image: boxfuse/flyway:latest
...
depends_on:
- my_sql_percona
deploy:
restart_policy:
condition: on-failure
Créez un cluster d'essaim (un nœud unique dans ce cas):
docker swarm init --advertise-addr <your-ip-address>
Déployez les services:
docker stack deploy --compose-file docker-compose.yml flyway_mysql
Le conteneur Flyway sera ensuite redémarré par essaim chaque fois qu'il sort avec une erreur, jusqu'à ce qu'il finisse par réussir.
Bien que cela semble fonctionner, je ne suis pas sûr que ce soit la meilleure approche dans ce cas. Par exemple, si le conteneur Flyway se ferme en raison d'une erreur dans un script de migration, swarm continuera de redémarrer le conteneur même s'il ne réussira jamais.
J'ai créé un référentiel avec ces cinq approches différentes.
Personnellement, je pense que j'utiliserais l'approche v2.1 car le bilan de santé est conservé avec le conteneur de base de données lui-même et non dupliqué dans chaque conteneur qui en dépend. Je n'ai pas besoin d'utiliser les services Swarm, alors choisissez ce qui vous convient. :-)
Avec la voie de migration 5.2.0, vous pouvez ajouter le paramètre connectRetries qui spécifie le nombre maximal de fois en intervalles de 1 seconde que la voie de migration tentera de se reconnecter.
command: -connectRetries=20 -url=jdbc:mysql://my_sql_db:3306/abhs?useUnicode=true&characterEncoding=utf8&useSSL=false -user=root -password=password migrate
vous pouvez également créer un migrate.dev.sh
et utilise docker run .. boxfuse/flyway:latest
etc..
voici un exemple de fichier
$FLYWAY_PASSWORD=$PGPASSWORD
$FLYWAY_URL=jdbc:postgresql://$DB_Host:$PORT/mydb
$FLYWAY_USER=postgres
docker run \
--rm \
-e FLYWAY_PASSWORD=$FLYWAY_PASSWORD \
-e FLYWAY_URL=$FLYWAY_URL \
-e FLYWAY_USER=$FLYWAY_USER \
-e FLYWAY_SCHEMAS=$FLYWAY_SCHEMAS \
-v $(pwd)/sql:/flyway/sql \
boxfuse/flyway:latest $1
et vous pouvez l'appeler comme ça
migrate.dev.sh info
ou migrate.dev.sh migrate
en supposant que vos migrations se trouvent dans ./sql/