Comment utiliser Confd et Etcd pour reconfigurer dynamiquement les services dans CoreOS

introduction

CoreOS vous permet d’exécuter facilement des services dans des conteneurs Docker sur un cluster de machines. La procédure pour ce faire implique généralement de démarrer une ou plusieurs instances d’un service, puis d’enregistrer chaque instance auprès deetcd, le magasin de valeurs-clés distribué de CoreOS.

En tirant parti de ce schéma, les services associés peuvent obtenir des informations précieuses sur l’état de l’infrastructure et utiliser ces connaissances pour informer leur propre comportement. Cela permet aux services de se configurer dynamiquement chaque fois que des valeursetcd importantes changent.

Dans ce guide, nous aborderons un outil appeléconfd, spécialement conçu pour surveiller les changements dans les magasins de valeurs-clés distribués. Il est exécuté à partir d'un conteneur Docker et est utilisé pour déclencher des modifications de configuration et des rechargements de service.

Prérequis et objectifs

Pour pouvoir parcourir ce guide, vous devez avoir une connaissance de base de CoreOS et de ses composants. Dans les guides précédents, nous avons configuré un cluster CoreOS et nous sommes familiarisés avec certains des outils utilisés pour gérer vos clusters.

Vous trouverez ci-dessous les guides que vous devriez lire avant de commencer cet article. Nous allons modifier le comportement de certains des services décrits dans ces guides. Par conséquent, même s'il est important de comprendre le contenu, vous devriez recommencer à zéro lorsque vous utilisez ce guide:

De plus, pour vous familiariser avec certains des outils de gestion que nous allons utiliser, vous souhaitez consulter ces guides:

Le guide «Comment créer des services flexibles» est particulièrement important pour ce guide, car les services principaux + sidekick basés sur un modèle serviront de base au service frontal que nous allons mettre en place dans ce guide. Comme nous l'avons indiqué précédemment, bien que les guides ci-dessus traitent de la création des services Apache et Sidekick, certaines modifications de la configuration de ce guide facilitent le démarrage à partir de zéro. Nous allons créer des versions modifiées de ces services dans ce guide.

Dans ce didacticiel, nous allons nous concentrer sur la création d’un nouveau conteneur d’applications avec Nginx. Cela servira de proxy inverse pour les différentes instances Apache que nous pouvons générer à partir de nos fichiers de modèle. Le conteneur Nginx sera configuré avecconfd pour surveiller l'enregistrement du service dont nos services compagnons sont responsables.

Nous allons commencer par le même groupe de trois machines que nous avons utilisé dans cette série.

  • coreos-1

  • coreos-2

  • coreos-3

Lorsque vous avez terminé de lire les guides précédents et que votre cluster de trois ordinateurs est disponible, continuez.

Configuration des services Apache dorsaux

Nous allons commencer par configurer nos services Apache d’arrière-plan. Cela reflètera principalement la dernière partie du guide précédent, mais nous allons parcourir toute la procédure ici en raison de quelques différences subtiles.

Connectez-vous à l’une de vos machines CoreOS pour commencer:

ssh -A core@ip_address

Configuration du conteneur Apache

Nous allons commencer par créer le conteneur Apache de base. Il s’agit en réalité du même guide que le dernier guide. Vous n’avez donc pas à le refaire si cette image est déjà disponible dans votre compte Docker Hub. Nous allons baser ce conteneur sur l'image de conteneur Ubuntu 14.04.

Nous pouvons extraire l'image de base et démarrer une instance de conteneur en tapant:

docker run -i -t ubuntu:14.04 /bin/bash

Vous serez placé dans une sessionbash une fois le conteneur démarré. À partir de là, nous mettrons à jour l'index du package localapt et installeronsapache2:

apt-get update
apt-get install apache2 -y

Nous allons également définir la page par défaut:

echo "

Running from Docker on CoreOS

" > /var/www/html/index.html

Nous pouvons quitter le conteneur maintenant puisqu'il se trouve dans l'état dont nous avons besoin:

exit

Connectez-vous ou créez votre compte sur Docker Hub en tapant:

docker login

Vous devrez fournir votre nom d'utilisateur, votre mot de passe et votre adresse électronique pour votre compte Docker Hub.

Ensuite, obtenez l'ID de conteneur de l'instance que vous venez de quitter:

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1db0c9a40c0d        ubuntu:14.04        "/bin/bash"         2 minutes ago       Exited (0) 4 seconds ago                       jolly_pare

Le champ en surbrillance ci-dessus est l'ID du conteneur. Copiez la sortie que vous voyez sur votre propre ordinateur.

Maintenant, validez en utilisant cet ID de conteneur, votre nom d'utilisateur Docker Hub et un nom pour l'image. Nous utiliserons “apache” ici:

docker commit 1db0c9a40c0d user_name/apache

Poussez votre nouvelle image sur Docker Hub:

docker push user_name/apache

Vous pouvez maintenant utiliser cette image dans vos fichiers de service.

Création du fichier d'unité de modèle de service Apache

Maintenant que vous disposez d'un conteneur, vous pouvez créer un fichier d'unité modèle afin quefleet etsystemd puissent gérer correctement le service.

Avant de commencer, mettons en place une structure de répertoires afin que nous puissions rester organisés:

cd ~
mkdir static templates instances

Maintenant, nous pouvons créer notre fichier modèle dans le répertoiretemplates:

vim templates/[email protected]

Collez les informations suivantes dans le fichier. Vous pouvez obtenir des détails sur chacune des options que nous utilisons en suivant le guide précédent surcreating flexible fleet unit files:

[Unit]
Description=Apache web server service on port %i

# Requirements
Requires=etcd.service
Requires=docker.service
Requires=apache-discovery@%i.service

# Dependency ordering
After=etcd.service
After=docker.service
Before=apache-discovery@%i.service

[Service]
# Let processes take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill apache.%i
ExecStartPre=-/usr/bin/docker rm apache.%i
ExecStartPre=/usr/bin/docker pull user_name/apache
ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PRIVATE_IPV4}:%i:80 \
user_name/apache /usr/sbin/apache2ctl -D FOREGROUND

# Stop
ExecStop=/usr/bin/docker stop apache.%i

[X-Fleet]
# Don't schedule on the same machine as other Apache instances
Conflicts=apache@*.service

Une modification que nous avons apportée ici consiste à utiliser l'interface privée à la place de l'interface publique. Étant donné que toutes nos instances Apache recevront le traficthrough du proxy inverse Nginx au lieu de gérer les connexions à partir du Web ouvert, c'est une bonne idée. N'oubliez pas que si vous utilisez l'interface privée sur DigitalOcean, l'indicateur de «réseau privé» doit avoir été sélectionné sur le serveur que vous avez démarré.

N'oubliez pas non plus de modifier lesuser_name pour référencer votre nom d'utilisateur Docker Hub afin de récupérer correctement le fichier Docker.

Création du fichier d'unité de modèle Sidekick

Maintenant, nous allons faire la même chose pour le service sidekick. Celui-ci nous modifierons légèrement en prévision des informations dont nous aurons besoin ultérieurement.

Ouvrez le fichier modèle dans votre éditeur:

vim templates/[email protected]

Nous utiliserons les informations suivantes dans ce fichier:

[Unit]
Description=Apache web server on port %i etcd registration

# Requirements
Requires=etcd.service
Requires=apache@%i.service

# Dependency ordering and binding
After=etcd.service
After=apache@%i.service
BindsTo=apache@%i.service

[Service]

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Start
## Test whether service is accessible and then register useful information
ExecStart=/bin/bash -c '\
  while true; do \
    curl -f ${COREOS_PRIVATE_IPV4}:%i; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PRIVATE_IPV4} \'${COREOS_PRIVATE_IPV4}:%i\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}; \
    fi; \
    sleep 20; \
  done'

# Stop
ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}

[X-Fleet]
# Schedule on the same machine as the associated Apache service
MachineOf=apache@%i.service

La configuration ci-dessus diffère à certains égards de celle du guide précédent. Nous avons ajusté la valeur définie par la commandeetcdctl set. Au lieu de transmettre un objet JSON, nous définissons une simple combinaison adresse IP / port. De cette façon, nous pouvons lire cette valeur directement pour trouver les informations de connexion nécessaires pour accéder à ce service.

Nous avons également ajusté les informations pour spécifier l'interface privée, comme nous l'avons fait dans notre autre fichier. Laissez ceci public si vous ne disposez pas de cette option.

Instancier vos services

Créons maintenant deux instances de ces services.

Commençons par créer les liens symboliques. Accédez au répertoire~/instances que vous avez créé et créez un lien pour définir les ports sur lesquels ils seront exécutés. Nous voulons exécuter un service sur le port 7777 et un autre sur le port 8888:

cd ~/instances
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]

Maintenant, nous pouvons démarrer ces services en passant le répertoire~/instances àfleet:

fleetctl start ~/instances/*

Après le démarrage de vos instances (cela peut prendre quelques minutes), vous devriez pouvoir voir les entréesetcd que vos acolytes ont créées:

etcdctl ls --recursive /
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore
/services
/services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

Si vous demandez la valeur d'une de ces entrées, vous pouvez voir que vous obtenez une adresse IP et un numéro de port:

etcdctl get /services/apache/10.132.249.206
10.132.249.206:8888

Vous pouvez utilisercurl pour récupérer la page et vous assurer qu’elle fonctionne correctement. Cela ne fonctionnera à partir de votre ordinateur que si vous avez configuré le service pour utiliser un réseau privé:

curl 10.132.249.206:8888

Running from Docker on CoreOS

Nous avons maintenant mis en place notre infrastructure d’arrière-plan. Notre prochaine étape est de se familiariser avecconfd afin que nous puissions surveiller l'emplacement de/services/apache dansetcd pour les changements et reconfigurer Nginx à chaque fois.

Création du conteneur Nginx

Nous allons démarrer le conteneur Nginx à partir de la même base Ubuntu 14.04 que celle utilisée pour les services Apache.

Installation du logiciel

Démarrez un nouveau conteneur en tapant:

docker run -i -t ubuntu:14.04 /bin/bash

Mettez à jour votre cache de paquetage localapt et installez Nginx. Nous devons également installercurl car l'image de base ne l'inclut pas et nous en avons besoin pour obtenir momentanément le package stableconfd de GitHub:

apt-get update
apt-get install nginx curl -y

Maintenant, nous pouvons accéder auxreleases page pourconfd sur GitHub dans nos navigateurs. Nous devons trouver le lien vers la dernière version stable. Au moment de la rédaction de cet article, c'estv0.5.0, mais cela peut avoir changé. Cliquez avec le bouton droit de la souris sur le lien de la version Linux de l'outil et sélectionnez «Copier l'adresse du lien» ou toute autre option similaire disponible.

De retour dans votre conteneur Docker, utilisez l’URL copiée pour télécharger l’application. Nous mettrons ceci dans le répertoire/usr/local/bin. Nous devons choisirconfd comme fichier de sortie:

cd /usr/local/bin
curl -L https://github.com/kelseyhightower/confd/releases/download/v0.5.0/confd-0.5.0<^>-linux-amd64 -o confd

Maintenant, rendez le fichier exécutable afin que nous puissions l’utiliser dans notre conteneur:

chmod +x confd

Nous devrions également profiter de cette opportunité pour créer la structure de configuration attendue parconfd. Ce sera dans le répertoire/etc:

mkdir -p /etc/confd/{conf.d,templates}

Créer un fichier de configuration Confd pour lire les valeurs etc

Maintenant que nos applications sont installées, nous devrions commencer à configurerconfd. Nous allons commencer par créer un fichier de configuration ou un fichier de ressources de modèle.

Les fichiers de configuration dansconfd sont utilisés pour configurer le service pour vérifier certaines valeurs deetcd et lancer des actions lorsque des changements sont détectés. Ceux-ci utilisent le format de fichierTOML, qui est facile à utiliser et assez intuitif.

Commencez par créer un fichier dans notre répertoire de configuration appelénginx.toml:

vi /etc/confd/conf.d/nginx.toml

Nous allons construire notre fichier de configuration ici. Ajoutez les informations suivantes:

[template]

# The name of the template that will be used to render the application's configuration file
# Confd will look in `/etc/conf.d/templates` for these files by default
src = "nginx.tmpl"

# The location to place the rendered configuration file
dest = "/etc/nginx/sites-enabled/app.conf"

# The etcd keys or directory to watch.  This is where the information to fill in
# the template will come from.
keys = [ "/services/apache" ]

# File ownership and mode information
owner = "root"
mode = "0644"

# These are the commands that will be used to check whether the rendered config is
# valid and to reload the actual service once the new config is in place
check_cmd = "/usr/sbin/nginx -t"
reload_cmd = "/usr/sbin/service nginx reload"

Le fichier ci-dessus contient des commentaires expliquant certaines des idées de base, mais nous pouvons passer en revue les options ci-dessous:

Directif Obligatoire? Type La description

src

Yes

Chaîne

Le nom du modèle qui sera utilisé pour rendre les informations. S'il est situé en dehors de/etc/confd/templates, le chemin complet doit être utilisé.

dest

Yes

Chaîne

Emplacement du fichier où le fichier de configuration rendu doit être placé.

keys

Yes

Tableau de chaînes

Les clésetcd dont le modèle a besoin pour être correctement rendues. Cela peut être un répertoire si le modèle est configuré pour gérer les clés enfants.

propriétaire

No

Chaîne

Le nom d'utilisateur qui sera propriétaire du fichier de configuration rendu.

groupe

No

Chaîne

Le groupe qui recevra la propriété de groupe du fichier de configuration rendu.

mode

No

Chaîne

Le mode d'autorisations octales qui doit être défini pour le fichier rendu.

check_cmd

No

Chaîne

La commande à utiliser pour vérifier la syntaxe du fichier de configuration rendu.

reload_cmd

No

Chaîne

La commande à utiliser pour recharger la configuration de l'application.

préfixe

No

Chaîne

Une partie de la hiérarchieetcd qui précède les clés dans la directivekeys. Cela peut être utilisé pour rendre le fichier.toml plus flexible.

Le fichier que nous avons créé nous dit quelques choses importantes sur le fonctionnement de notre instanceconfd. Notre conteneur Nginx utilisera un modèle stocké à/etc/confd/templates/nginx.conf.tmpl pour rendre un fichier de configuration qui sera placé à/etc/nginx/sites-enabled/app.conf. Le fichier recevra un ensemble d'autorisations de0644 et la propriété sera donnée à l'utilisateur root.

L'applicationconfd recherchera les modifications au nœud/services/apache. Lorsqu'un changement est observé,confd interrogera les nouvelles informations sous ce nœud. Il rendra ensuite une nouvelle configuration pour Nginx. Il vérifiera les erreurs de syntaxe dans le fichier de configuration et rechargera le service Nginx une fois le fichier en place.

Nous avons maintenant créé notre fichier de ressources de modèle. Nous devrions travailler sur le fichier de modèle qui sera utilisé pour rendre notre fichier de configuration Nginx.

Créer un fichier de modèle confd

Pour notre fichier modèle, nous utiliserons un exemple du projetconfdGitHub documentation pour nous aider à démarrer.

Créez le fichier que nous avons référencé dans notre fichier de configuration ci-dessus. Mettez ce fichier dans notre répertoiretemplates:

vi /etc/confd/templates/nginx.tmpl

Dans ce fichier, nous créons simplement un fichier de configuration de proxy inverse Nginx standard. Cependant, nous utiliserons une syntaxe de modèle Go pour remplacer certaines des informations queconfd extrait deetcd.

Tout d'abord, nous configurons le bloc avec les serveurs «amont». Cette section permet de définir le pool de serveurs auquel Nginx peut envoyer des requêtes. Le format est généralement comme ceci:

upstream pool_name {
    server server_1_IP:port_num;
    server server_2_IP:port_num;
    server server_3_IP:port_num;
}

Cela nous permet de transmettre des requêtes auxpool_name et Nginx sélectionnera l'un des serveurs définis à qui transmettre la requête.

L'idée derrière notre fichier de modèle est d'analyseretcd pour les adresses IP et les numéros de port de nos serveurs Web Apache. Ainsi, au lieu de définir statiquement nos serveurs en amont, nous devrions renseigner dynamiquement ces informations lors du rendu du fichier. Nous pouvons le faire en utilisantGo templates pour le contenu dynamique.

Pour ce faire, nous utiliserons plutôt ceci comme notre bloc:

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

Expliquons un instant ce qui se passe. Nous avons ouvert un bloc pour définir un pool de serveurs en amont appeléapache_pool. A l'intérieur, nous spécifions que nous commençons un code de langue Go en utilisant les doubles crochets.

Entre ces crochets, nous spécifions le point de terminaisonetcd où se trouvent les valeurs qui nous intéressent. Nous utilisons unrange pour rendre la liste itérable.

Nous l'utilisons pour transmettre toutes les entrées récupérées sous l'emplacement/services/apache dansetcd dans le blocrange. Nous pouvons alors obtenir la valeur de la clé dans l'itération actuelle en utilisant un seul point dans les "\ {\ {" et "}}" qui indiquent une valeur insérée. Nous l'utilisons dans la boucle de plage pour remplir le pool de serveurs. Enfin, nous terminons la boucle avec la directive{{ end }}.

Note: n'oubliez pas d'ajouter le point-virgule après la directiveserver dans la boucle. Si vous oubliez cela, la configuration ne fonctionnera pas.

Après avoir configuré le pool de serveurs, nous pouvons simplement utiliser une passe proxy pour diriger toutes les connexions dans ce pool. Ce sera simplement un bloc de serveur standard en tant que proxy inverse. La seule chose à noter est leaccess_log, qui utilise un format personnalisé que nous allons créer momentanément:

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    access_log /var/log/nginx/access.log upstreamlog;

    location / {
        proxy_pass http://apache_pool;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Cela répondra à toutes les connexions sur le port 80 et les passera au pool de serveurs àapache_pool qui est généré en regardant les entréesetcd.

Pendant que nous traitons de cet aspect du service, nous devrions supprimer le fichier de configuration par défaut de Nginx afin d'éviter tout conflit ultérieur. Nous allons simplement supprimer le lien symbolique permettant la configuration par défaut:

rm /etc/nginx/sites-enabled/default

C'est également le bon moment pour configurer le format de journal que nous avons référencé dans notre fichier de modèle. Cela doit aller dans le blochttp de la configuration, qui est disponible dans le fichier de configuration principal. Ouvrez ça maintenant:

vi /etc/nginx/nginx.conf

Nous ajouterons une directivelog_format pour définir les informations que nous voulons enregistrer. Il enregistrera le client qui visite, ainsi que le serveur principal auquel la demande est transmise. Nous allons enregistrer quelques données sur la durée de ces procédures:

. . .
http {
    ##
    # Basic Settings
    ##
    log_format upstreamlog '[$time_local] $remote_addr passed to: $upstream_addr: $request Upstream Response Time: $upstream_response_time Request time: $request_time';

    sendfile on;
    . . .

Enregistrez et fermez le fichier lorsque vous avez terminé.

Création d'un script pour exécuter Confd

Nous devons créer un fichier script qui appelleraconfd avec notre fichier de ressources modèle et notre fichier modèle aux moments appropriés.

Le script doit faire deux choses pour que notre service fonctionne correctement:

  • Il doit s'exécuter au lancement du conteneur pour configurer les paramètres Nginx initiaux en fonction de l'état actuel de l'infrastructure dorsale.

  • Il doit continuer à surveiller les modifications de l'enregistrement deetcd pour les serveurs Apache afin de pouvoir reconfigurer Nginx en fonction des serveurs principaux disponibles.

Nous obtiendrons notre script deMarcel de Graaf’s GitHub page. C'est un script simple et agréable qui faitexactly ce dont nous avons besoin. Nous ne ferons que quelques modifications mineures pour notre scénario.

Plaçons ce script à côté de notre exécutableconfd. Nous appellerons celaconfd-watch:

vi /usr/local/bin/confd-watch

Nous commencerons par l'en-tête classiquebash pour identifier l'interpréteur dont nous avons besoin. Nous allons ensuite définir certaines options debash afin que le script échoue immédiatement en cas de problème. Il renverra la valeur de la dernière commande à échouer ou à exécuter.

#!/bin/bash

set -eo pipefail

Ensuite, nous voulons configurer certaines variables. En utilisant la substitution de paramètre debash, nous définirons les valeurs par défaut, mais intégrons une certaine flexibilité pour nous permettre de remplacer les valeurs codées en dur lors de l'appel du script. En gros, il suffit de configurer chaque composant de l’adresse de connexion indépendamment, puis de les regrouper pour obtenir l’adresse complète requise.

La substitution de paramètre est créée avec cette syntaxe:${var_name:-default_value}. Cela a la propriété d'utiliser la valeur devar_name si elle est donnée et non nulle, sinon par défaut surdefault_value.

Nous utilisons par défaut les valeurs queetcd attend par défaut. Cela permettra à notre script de bien fonctionner sans informations supplémentaires, mais nous pouvons le personnaliser si nécessaire lorsque vous appelez le script:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

Nous allons maintenant utiliserconfd pour rendre une version initiale du fichier de configuration Nginx en lisant les valeurs deetcd disponibles lorsque ce script est appelé. Nous utiliserons une boucleuntil pour essayer en permanence de construire la configuration initiale.

La construction en boucle peut être nécessaire dans le cas oùetcd n'est pas disponible tout de suite ou dans le cas où le conteneur Nginx est mis en ligne avant les serveurs principaux. Cela lui permet d'interrogeretcd à plusieurs reprises jusqu'à ce qu'il puisse enfin produire une configuration initiale valide.

La commande réelleconfd que nous appelons s'exécute une fois, puis se termine. Cela nous permet d'attendre 5 secondes jusqu'à la prochaine exécution pour donner à nos serveurs principaux une chance de s'inscrire. Nous nous connectons à la variableETCD complète que nous avons construite en utilisant les paramètres par défaut ou passés en paramètres, et nous utilisons le fichier de ressources modèle pour définir le comportement de ce que nous voulons faire:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD"

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration"
    sleep 5
done

Une fois la configuration initiale définie, la tâche suivante de notre script doit être de mettre en place un mécanisme d’interrogation continue. Nous voulons nous assurer que les modifications futures sont détectées afin que Nginx soit mis à jour.

Pour ce faire, nous pouvons appeler à nouveauconfd. Cette fois, nous voulons définir un intervalle d'interrogation continu et placer le processus en arrière-plan afin qu'il s'exécute indéfiniment. Nous transmettrons les mêmes informations de connexionetcdet le même fichier de ressources de modèle puisque notre objectif est toujours le même.

Après avoir mis le processusconfd en arrière-plan, nous pouvons démarrer Nginx en toute sécurité en utilisant le fichier de configuration créé. Ce script étant appelé notre commande "exécuter" de Docker, nous devons le laisser fonctionner au premier plan afin que le conteneur ne se ferme pas à ce stade. Pour ce faire, il suffit de suivre les journaux, ce qui nous donne accès à toutes les informations que nous enregistrons:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD."

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration."
    sleep 5
done

# Put a continual polling `confd` process into the background to watch
# for changes every 10 seconds
confd -interval 10 -node $ETCD -config-file /etc/confd/conf.d/nginx.toml &
echo "[nginx] confd is now monitoring etcd for changes..."

# Start the Nginx service using the generated config
echo "[nginx] starting nginx service..."
service nginx start

# Follow the logs to allow the script to continue running
tail -f /var/log/nginx/*.log

Lorsque vous avez terminé, enregistrez et fermez le fichier.

La dernière chose à faire est de rendre le script exécutable:

chmod +x /usr/local/bin/confd-watch

Quittez le conteneur maintenant pour revenir au système hôte:

exit

S'engager et pousser le conteneur

Maintenant, nous pouvons valider le conteneur et le placer sur Docker Hub afin qu'il soit disponible pour nos machines.

Découvrez l'ID du conteneur:

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
de4f30617499        ubuntu:14.04        "/bin/bash"         22 hours ago        Exited (0) About a minute ago                       stupefied_albattani

La chaîne en surbrillance est l'ID de conteneur dont nous avons besoin. Commettez le conteneur à l'aide de cet ID avec votre nom d'utilisateur Docker Hub et le nom que vous souhaitez utiliser pour cette image. Nous allons utiliser le nom «nginx_lb» dans ce guide:

docker commit de4f30617499 user_name/nginx_lb

Connectez-vous à votre compte Docker Hub si nécessaire:

docker login

Maintenant, vous devriez augmenter votre image engagée afin que vos autres hôtes puissent la réduire si nécessaire:

docker push user_name/nginx_lb

Construire le fichier d'unité statique Nginx

L'étape suivante consiste à créer un fichier d'unité qui démarrera le conteneur que nous venons de créer. Cela nous permettra d'utiliserfleet pour contrôler le processus.

Comme ce ne sera pas un modèle, nous le placerons dans le répertoire~/static que nous avons créé au début de ce répertoire:

vim static/nginx_lb.service

Nous allons commencer par la section standard[Unit] pour décrire le service et définir les dépendances et l'ordre:

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

Ensuite, nous devons définir la partie[Service] du fichier. Nous allons définir le délai d'attente à zéro et ajuster le killmode à nouveau, comme nous l'avons fait avec les fichiers de service Apache. Nous allons extraire à nouveau le fichier d'environnement afin de pouvoir accéder aux adresses IP publique et privée de l'hôte sur lequel ce conteneur est exécuté.

Nous allons ensuite nettoyer notre environnement pour nous assurer que toutes les versions précédentes de ce conteneur sont supprimées et supprimées. Nous tirons le conteneur que nous venons de créer pour nous assurer de toujours avoir la version la plus récente.

Enfin, nous allons commencer le conteneur. Cela implique de démarrer le conteneur, de lui donner le nom que nous avons référencé dans les commandes remove et kill et de lui transmettre l'adresse IP publique de l'hôte sur lequel il est exécuté pour mapper le port 80. Nous appelons le scriptconfd-watch que nous avons écrit comme commande d'exécution.

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

Maintenant, tout ce dont nous avons besoin pour trier est la commande d'arrêt et les directions de planification defleet. Nous voulons que ce conteneur soit uniquement initié sur des hôtes qui n'exécutent pas d'autres instances d'équilibrage de charge ou des serveurs Apache dorsaux. Cela permettra à notre service de répartir efficacement la charge:

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

# Stop
ExecStop=/usr/bin/docker stop nginx_lb

[X-Fleet]
Conflicts=nginx.service
Conflicts=apache@*.service

Enregistrez et fermez le fichier lorsque vous avez terminé.

Exécution de l’équilibreur de charge Nginx

Vous devriez déjà avoir deux instances Apache en cours d'exécution à partir de plus tôt dans le tutoriel. Vous pouvez vérifier en tapant:

fleetctl list-units
UNIT                MACHINE             ACTIVE  SUB
[email protected]   197a1662.../10.132.249.206  active  running
[email protected]   04856ec4.../10.132.249.212  active  running
[email protected]     197a1662.../10.132.249.206  active  running
[email protected]     04856ec4.../10.132.249.212  active  running

Vous pouvez également vérifier qu'ils s'enregistrent correctement avecetcd en tapant:

etcdctl ls --recursive /services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

Nous pouvons maintenant essayer de démarrer notre service Nginx:

fleetctl start ~/static/nginx_lb.service
Unit nginx_lb.service launched on 96ec72cf.../10.132.248.177

Le démarrage du service peut prendre environ une minute, en fonction du temps nécessaire à la suppression de l'image. Après son démarrage, si vous vérifiez les journaux avec la commandefleetctl journal, vous devriez pouvoir voir certaines informations du journal deconfd. Ça devrait ressembler a quelque chose comme ca:

fleetctl journal nginx_lb.service
-- Logs begin at Mon 2014-09-15 14:54:05 UTC, end at Tue 2014-09-16 17:13:58 UTC. --
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
Sep 16 17:13:48 lala1 docker[15379]: [nginx] confd is monitoring etcd for changes...
Sep 16 17:13:48 lala1 docker[15379]: [nginx] starting nginx service...
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/access.log <==
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/error.log <==
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO /etc/nginx/sites-enabled/app.conf has md5sum a8517bfe0348e9215aa694f0b4b36c9b should be 33f42e3b7cc418f504237bea36c8a03e
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated

Comme vous pouvez le voir,confd s'est tourné versetcd pour sa configuration initiale. Il a ensuite démarrénginx. Ensuite, nous pouvons voir les lignes où les entrées deetcdont été réévaluées et un nouveau fichier de configuration créé. Si le fichier nouvellement généré ne correspond pas auxmd5sum du fichier en place, le fichier est désactivé et le service est rechargé.

Cela permet à notre service d'équilibrage de charge de suivre en fin de compte nos serveurs dorsaux Apache. Siconfd semble se mettre à jour en permanence, cela peut être dû au fait que vos instances Apache actualisent trop souvent leur TTL. Pour éviter cela, vous pouvez augmenter les valeurs de veille et de durée de vie dans le modèle de sidekick.

Pour voir l'équilibreur de charge en action, vous pouvez demander le fichier/etc/environments à l'hôte qui exécute le service Nginx. Ceci contient l'adresse IP publique de l'hôte. Si vous souhaitez améliorer cette configuration, envisagez d'exécuter un service d'accompagnement qui enregistre ces informations avecetcd, comme nous l'avons fait pour les instances Apache:

fleetctl ssh nginx_lb cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.248.177
COREOS_PUBLIC_IPV4=104.131.16.222

Maintenant, si nous allons à l'adresse IPv4 publique dans notre navigateur, nous devrions voir la page que nous avons configurée dans nos instances Apache:

Apache index page

À présent, si vous examinez à nouveau vos journaux, vous devriez être en mesure de voir les informations indiquant le serveur principal auquel la demande a été effectivement transmise:

fleetctl journal nginx_lb
. . .
Sep 16 18:04:38 lala1 docker[18079]: 2014-09-16T18:04:38Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: 2014-09-16T18:04:48Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: [16/Sep/2014:18:04:48 +0000] 108.29.37.206 passed to: 10.132.249.212:8888: GET / HTTP/1.1 Upstream Response Time: 0.003 Request time: 0.003

Conclusion

Comme vous pouvez le voir, il est possible de configurer vos services pour vérifieretcd pour les détails de configuration. Des outils commeconfd peuvent rendre ce processus relativement simple en permettant une interrogation continue des entrées significatives.

Dans l'exemple de ce guide, nous avons configuré notre service Nginx pour utiliseretcd pour générer sa configuration initiale. Nous l'avons également configuré en arrière-plan pour vérifier en permanence les modifications. Ceci, combiné à la génération de configuration dynamique basée sur des modèles, nous a permis d'avoir systématiquement une image à jour de nos serveurs principaux.