Я проводил некоторые исследования и столкнулся с аналогичной проблемой на сайте Консул github , где пользователь впитывает , предлагает использовать планеры / регистратор в качестве моста между менеджером Консул и агенты.
Моя версия, приведенная ниже, немного отличается от его (в основном это имена контейнеров, соответствующих моим значениям по умолчанию в коде Spring Boot, без SSL и т. Д.), Но без ввода большинства из них была бы ошибкой! 117] Я создал свою оверлейную сеть Swarm следующим образом:
docker network create -d overlay --opt com.docker.network.swarm.name=smartdeploy_evo smartdeploy_evo
, а затем использовал файл Compose, показанный в конце этого поста, который я развернул с узла Manager следующим образом:
docker stack deploy -c consul.yml consul
[ 119] с файлом consul.yml, определенным следующим образом:
version: "3.4"
networks:
smartdeploy_evo:
external: true
volumes:
consul:
services:
consul:
image: consul:0.9.3
volumes:
- consul:/consul
ports:
- target: 8500
published: 8500
mode: host
networks:
smartdeploy_evo:
aliases:
- consul.cluster
environment:
- 'CONSUL_LOCAL_CONFIG={ "skip_leave_on_interrupt": true,
"data_dir":"/consul/data",
"server":true }'
- CONSUL_BIND_INTERFACE=eth0
command: agent -ui -data-dir /consul/data -server -client 0.0.0.0 -bootstrap-expect=1 -retry-join consul.cluster
deploy:
endpoint_mode: dnsrr
mode: global
placement:
constraints: [node.role == manager]
consul_client:
image: consul:0.9.3
volumes:
- consul:/consul
networks:
smartdeploy_evo:
aliases:
- consul.client.cluster
environment:
- 'CONSUL_LOCAL_CONFIG={ "skip_leave_on_interrupt": true,
"data_dir":"/consul/data" }'
- CONSUL_BIND_INTERFACE=eth0
command: agent -ui -data-dir /consul/data -client 0.0.0.0 -retry-join consul.cluster
deploy:
endpoint_mode: dnsrr
mode: global
placement:
constraints: [node.role != manager]
consul_registrator:
image: gliderlabs/registrator:master
command: -internal consul://consul.cluster:8500
volumes:
- /var/run/docker.sock:/tmp/docker.sock
networks:
- smartdeploy_evo
deploy:
mode: global
Я стараюсь не использовать функции c-стиля аргумента var по двум главным причинам:
Я сделал путь, который работает с помощью boost::fusion
, которому дают аргументы безопасным с точки зрения типов способом. Это выполняет итерации по тем аргументам, распечатывая их когда a %
встречен. Если лишь немногим или слишком многим аргументам дали, исключение выдается.
Все еще существует одна проблема: макросы Variadic еще не являются стандартными в C++. Так, я сделал две версии. Тот, которые работают с текущим C++. Необходимо вызвать его использование
dprintf("name: %, value: %\n", ("foo", 42));
Затем. Другая версия, с помощью variadic макросы, может использоваться путем определения символа препроцессора, который позволяет Вам записать
dprintf("name: %, value: %\n", "foo", 42);
Вот код. boost.fusion
предоставляет больше подробную информацию для этого:
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/next.hpp>
#include <stdexcept>
#include <iostream>
template<typename IterS, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqE, IterSeqE) {
while(b != e) {
if(*b == '%') {
if(++b != e && *b == '%') {
std::cout << '%';
} else {
throw std::invalid_argument("too many '%'");
}
} else {
std::cout << *b;
}
++b;
}
}
template<typename IterS, typename IterSeqB, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqB seqb, IterSeqE seqe) {
while(b != e) {
if(*b == '%') {
if(++b != e && *b == '%') {
std::cout << '%';
} else {
std::cout << *seqb;
return print_vec(b, e, next(seqb), seqe);
}
} else {
std::cout << *b;
}
++b;
}
throw std::invalid_argument("too few '%'");
}
template<typename Seq>
void print_vec(std::string const& msg, Seq const& seq) {
print_vec(msg.begin(), msg.end(), begin(seq), end(seq));
}
#ifdef USE_VARIADIC_MACRO
# ifdef DEBUG
# define dprintf(format, ...) \
print_vec(format, boost::fusion::make_vector(__VA_ARGS__))
# else
# define dprintf(format, ...)
# endif
#else
# ifdef DEBUG
# define dprintf(format, args) \
print_vec(format, boost::fusion::make_vector args)
# else
# define dprintf(format, args)
# endif
#endif
// test, using the compatible version.
int main() {
dprintf("hello %, i'm % years old\n", ("litb", 22));
}
#ifdef DEBUG
#define dprintf(format, ...) real_dprintf(format, __VA_ARGS__)
#else
#define dprintf
#endif
Здесь real_dprintf () является "реальной" функцией, которая вызывается, и dprintf () является просто макросом, переносящим вызов.
Решение для препроцессора будет работать, но это может быть раздражающим для восстановления для изменения от одного до другого. Я буду часто принимать решение во время выполнения. Я сначала объявляю:
static void do_nothing(const char *fmt, ...) { (void)fmt; }
extern void real_dprintf(const char *fmt, ...);
void (*dprintf)(const char *fmt, ...) = do_nothing;
Затем в коде инициализации я имею
if (getenv("APPLICATION") && strstr(getenv("APPLICATION"), "dprintf"))
dprintf = real_dprintf;
Таким образом, я могу быстро изменить режимы путем изменения значения переменной среды.