2014-02-06 4 views
2

В настоящее время я занимаюсь CoreOS и создаю кластер на основе этого. До сих пор опыт работы с CoreOS на одном хосте довольно плавный. Но дело доходит до обнаружения сервисов. Почему-то я не получаю общую идею, поэтому я прошу здесь сейчас о помощи.Как бороться с устаревшими данными при выполнении поиска сервисов с помощью etcd на CoreOS?

Что я хочу сделать, так это иметь два контейнера Docker, где первый полагается на второй. Если мы говорим о чистом Докере, я могу решить это, используя linked containers. Все идет нормально.

Но этот подход не работает через границы машины, поскольку Docker не может связывать контейнеры через несколько хостов. Поэтому мне интересно, как это сделать.

Что я понял до сих пор, так это то, что идея CoreOS о том, как с этим бороться, заключается в использовании ее службы etcd, которая в основном представляет собой распределенное хранилище ключей, доступное на каждом узле локально через порт 4001, поэтому вам не нужно иметь дело (как потребитель etcd) с любыми сетевыми данными: просто получите доступ к localhost:4001, и все в порядке.

Так, в моей голове, теперь у меня есть идея, что это означает, что, когда Докер, который обеспечивает сервис раскручивается, он регистрирует себя (т.е. его IP-адрес и порт) в локальной etcd и etcd ухаживает распространения информации по сети. Этот способ, например, Вы получаете пар ключ-значение, такие как:

RedisService => 192.168.3.132:49236 

Теперь, когда другой контейнер Docker необходим доступ к RedisService, он получает IP-адрес и порт от их собственный местный etcd, по крайней мере, когда информация была распространена по всей сети. Все идет нормально.

Но теперь у меня есть вопрос, на который я не могу ответить, и это меня озадачивает уже несколько дней: что происходит, когда служба уходит? Кто очищает данные внутри etcd? Если он не очищен, все клиенты пытаются получить доступ к службе, которая больше не существует.

Единственное (надежное) решение, которое я могу представить на данный момент, использует функцию TTL etcd для данных, но это связано с компромиссом: либо у вас довольно высокий сетевой трафик, как вам нужно отправить сердцебиение каждые несколько секунд, или вы должны жить со устаревшими данными. Оба не в порядке.

Другой, ну, «решение» Я могу думать о том, чтобы сделать сам сервис разрегистрацию, когда он идет вниз, но это работает только для плановых отключений, а не для аварий, силовых outeages, ...

Итак, как вы это решаете?

ответ

8

Существует несколько способов решения этой проблемы: метод sidekick, используя ExecStopPost и удаляя при сбое. Я принимаю трио CoreOS, etcd и systemd, но эти понятия могут применяться и в других местах.

кореша Метод

Это включает в себя запуск отдельного процесса рядом с основным приложением, что сердцебиений в etcd. С простой стороны это всего лишь цикл for, который работает вечно. Вы можете использовать BindsTo systemd, чтобы гарантировать, что когда ваш основной блок остановится, этот блок регистрации службы также остановится. В ExecStop вы можете явно удалить установленный вами ключ.Мы также устанавливаем TTL продолжительностью 60 секунд, чтобы справиться с какой-либо неуважительной остановкой.

[Unit] 
Description=Announce nginx1.service 
# Binds this unit and nginx1 together. When nginx1 is stopped, this unit will be stopped too. 
BindsTo=nginx1.service 

[Service] 
ExecStart=/bin/sh -c "while true; do etcdctl set /services/website/nginx1 '{ \"host\": \"10.10.10.2\", \"port\": 8080, \"version\": \"52c7248a14\" }' --ttl 60;sleep 45;done" 
ExecStop=/usr/bin/etcdctl delete /services/website/nginx1 

[Install] 
WantedBy=local.target 

На комплексной стороне, это может быть контейнером, который запускается и попадет в /health конечной точки, что ваше приложение обеспечивает, чтобы запустить проверку работоспособности перед отправкой данных в etcd.

ExecStopPost

Если вы не хотите, чтобы запустить что-то рядом с вашим основным приложением, вы можете иметь etcdctl команды внутри основного блока для работы на пуска и останова. Имейте в виду, что это не поймает всех неудач, как вы упомянули.

[Unit] 
Description=MyWebApp 
After=docker.service 
Require=docker.service 
After=etcd.service 
Require=etcd.service 

[Service] 
ExecStart=/usr/bin/docker run -rm -name myapp1 -p 8084:80 username/myapp command 
ExecStop=/usr/bin/etcdctl set /services/myapp/%H:8084 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\" }' 
ExecStopPost=/usr/bin/etcdctl rm /services/myapp/%H:8084 

[Install] 
WantedBy=local.target 

% H - системная переменная, которая заменяет имя хоста для машины. Если вы заинтересованы в более широком использовании переменных, ознакомьтесь с руководством CoreOS Getting Started with systemd.

Удаление при сбое

На стороне клиента, вы можете удалить любой экземпляр, который не удалось подключиться к более чем Х раз. Если вы получите 500 или тайм-аут от /services/myapp/instance1, вы можете запустить и продолжать увеличивать количество сбоев, а затем попытаться подключиться к другим хостам в каталоге /services/myapp/.

etcdctl set /services/myapp/instance1 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\", \"failures\": 1 }' 

Когда вы нажмете нужный порог, удалите ключ с etcdctl.

Что касается сетевого трафика, который может вызвать сердечный приступ - в большинстве случаев вы должны отправлять этот трафик через локальную частную сеть, в которой работает ваш провайдер, поэтому он должен быть бесплатным и очень быстрым. etcd постоянно встревоживает своих сверстников, так что это лишь небольшое увеличение трафика.

Перейдите в #coreos на Freenode, если у вас есть другие вопросы!

+0

Большое спасибо, это мне очень помогло :-)! –