По вашему запросу ничего не найдено :(
Убедитесь, что запрос написан правильно, или посмотрите другие наши статьи:
img
Что это вообще такое? Docker Compose является инструментом для определения и запуска контейнерных приложений. С Compose вы получаете возможность настраивать службы используя файл YAML. С помощью одной команды Compose вы создаете и запускаете все службы в соответствии с вашей конфигурацией. Установка начинается с создания каталога проекта: $ mkdir composetest $ cd composetest Создайте файл под названием app.py и вставьте в него следующие данные: import time import redis from flask import Flask app = Flask(__name__) cache = redis.Redis(host='redis', port=6379) def get_hit_count(): retries = 5 while True: try: return cache.incr('hits') except redis.exceptions.ConnectionError as exc: if retries == 0: raise exc retries -= 1 time.sleep(0.5) @app.route('/') def hello(): count = get_hit_count() return 'Hello World! I have been seen {} times. '.format(count) В нашем случае название хоста - redis, который использует порт 6379. Создайте файл под названием needs.txt в каталоге вашего проекта и вставьте его в: flask Redis Теперь следует написать код для файла Dockerfile, содержащий все необходимые переменные для среды разработки. В каталоге вашего проекта создайте файл с именем Dockerfile (файл будет определять среду приложения) и вставьте следующее содержимое: FROM python:3.7-alpine WORKDIR /code ENV FLASK_APP app.py ENV FLASK_RUN_HOST 0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers COPY requirements.txt requirements.txt RUN pip install -r requirements.txt COPY . . CMD ["flask", "run"] Определение сервисов осуществляется при создании файла с именем docker-compose.yml в каталоге вашего проекта со следующей информацией: version: '3' services: web: build: . ports: - "5000:5000" redis: image: "redis:alpine" На основании содержания файла происходит запуск двух сервисов: Web и Redis, а в дальнейшем вы можете вносить в этот файл различные БД и иную важную информацию. C помощью команды Compose создайте ваше приложение, после чего из каталога проекта запустите приложение, запустив docker-compose. Вот так: $ docker-compose up Creating network "composetest_default" with the default driver Creating composetest_web_1 ... Creating composetest_redis_1 ... Creating composetest_web_1 Creating composetest_redis_1 ... done Attaching to composetest_web_1, composetest_redis_1 web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) redis_1 | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo redis_1 | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started redis_1 | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf web_1 | * Restarting with stat redis_1 | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379. redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. web_1 | * Debugger is active! redis_1 | 1:M 17 Aug 22:11:10.483 # Server initialized redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. web_1 | * Debugger PIN: 330-787-903 redis_1 | 1:M 17 Aug 22:11:10.483 * Ready to accept connections Compose извлекает образ Redis, создавая образ для вашего приложения и запускает выбранные службы. В этом случае код копируется в образ во время сборки. Как вам такое? Теперь попробуйте ввести http://localhost:5000/ в браузере, чтобы чекнуть запущенное приложение. Если вы используете Docker для Linux, Docker Desktop для Mac или Docker Desktop для Windows, то теперь веб-приложение должно "смотреть" на порт 5000 на хосте Docker. Введите в своем веб-браузере адрес http://localhost:5000, чтобы увидеть сообщение Hello World. Если не сработает, вы также можете попробовать зайти на http://127.0.0.1:5000. Если вы используете Docker Machine на Mac или Windows, используйте ip MACHINE_VM docker-machine для получения IP-адреса вашего хоста Docker. Затем откройте http://MACHINE_VM_IP:5000 в браузере. Вы должны увидеть сообщение в своем браузере: Hello World! I have been seen 1 times. Переключитесь на другое окно терминала и введите docker image ls, чтобы вывести список локальных образов/контейнеров. Вывод на этом этапе должен показывать redis и web. $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE composetest_web latest e2c21aa48cc1 4 minutes ago 93.8MB python 3.4-alpine 84e6077c7ab6 7 days ago 82.5MB redis alpine 9d8fa9aa0e5b 3 weeks ago 27.5MB Важно: Вы можете просматривать запущенные контейнеры с помощью Docker Inspect Tag или ID Запустите docker-compose из каталога вашего проекта во втором терминале, либо нажмите CTRL + C в исходном терминале, где приложение уже запущено и отредактируйте файл Compose. Отредактируйте docker-compose.yml в каталоге вашего проекта для внесения той или иной правки в веб-службе version: '3' services: web: build: . ports: - "5000:5000" volumes: - .:/code environment: FLASK_ENV: development redis: image: "redis:alpine" Новый ключ редактирует каталог проекта на хосте внутри контейнера, что позволяет изменять код без необходимости перестраивать весь образ. Ключ среды устанавливает переменную FLASK_ENV, которая сообщает о запуске в режиме разработки и перезагрузке кода при изменении. Важно: этот режим должен использоваться только при разработке. В каталоге проекта введите docker-compose up, чтобы создать приложение с обновленным файлом Compose, и запустите его. $ docker-compose up Creating network "composetest_default" with the default driver Creating composetest_web_1 ... Creating composetest_redis_1 ... Creating composetest_web_1 Creating composetest_redis_1 ... done Attaching to composetest_web_1, composetest_redis_1 web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) … Поскольку код приложения теперь добавляется в контейнер с помощью тома, вы можете вносить изменения в его код и мгновенно просматривать изменения без необходимости перестраивать образ. Измените сообщение в app.py и сохраните его: Hello from Docker!: return 'Hello from Docker! I have been seen {} times. '.format(count) Обновите результат в вашем браузере (нажмите F5 или Ctrl + F5) . Приветствие должно быть обновлено, а счетчик должен увеличиваться. Вы можете поэкспериментировать с другими командами. Если вы хотите запускать свои службы в фоновом режиме, вы можете сделать следующее: docker-compose up and use docker-compose ps to see what is currently running: $ docker-compose up -d Starting composetest_redis_1... Starting composetest_web_1... $ docker-compose ps Name Command State Ports ------------------------------------------------------------------- composetest_redis_1 /usr/local/bin/run Up composetest_web_1 /bin/sh -c python app.py Up 5000->5000/tcp Команда docker-compose run позволяет вам применять одноразовые команды к вашим сервисов. Например, чтобы увидеть, какие переменные среды доступны для веб-службы: $ docker-compose run web env Выполните команду docker-compose –help, чтобы увидеть весь список доступных команд. Если вы запустили Compose с помощью docker-compose up -d, то нужно будет остановить ваши службы после работы с ними, для этого поможет команда ниже:$ docker-compose stop Если хотите полностью уничтожить контейнер, используйте команду down.
img
Предыдущий материал из цикла про ARP в IPv4. Ждет вас по ссылке. Как хост может узнать, следует ли пытаться отправить пакет хосту через сегмент, к которому он подключен, или отправить пакет на маршрутизатор для дальнейшей обработки? Если хост должен отправлять пакеты на маршрутизатор для дальнейшей обработки, как он может узнать, на какой маршрутизатор (если их несколько) отправлять трафик? Эти две проблемы вместе составляют проблему шлюза по умолчанию. Для IPv4 проблему довольно легко решить, используя префикс и длину префикса. Рисунок ниже демонстрирует нам это. Реализации IPv4 предполагают, что любой хост в пределах одной подсети IPv4 должен быть физически подключен к одному проводу. Как реализация может определить разницу? Маска подсети - это еще одна форма длины префикса, которая указывает, где заканчивается сетевой адрес и начинается адрес хоста. В этом случае предположим, что длина префикса равна 24 битам, или сетевой адрес равен /24. 24 указывает вам, сколько битов задано в маске подсети: 24 bits = 11111111.11111111.11111111.0000000 Поскольку в IPv4 используется десятичная запись маски, это также можно записать как 255.255.255.0. Чтобы определить, находится ли C на том же проводе, что и A, A будет: Логическое умножение маски подсети с адресом локального интерфейса Логическое умножение маски подсети с адресом назначения Сравните два результата; если они совпадают, целевой хост находится на том же канале связи, что и локальный интерфейс На рисунке ниже это продемонстрировано. На рисунке выше показано четыре IPv4-адреса; предположим, что A должен отправлять пакеты в C, D и E. Если A знает, что длина префикса локального сегмента составляет 24 бита либо с помощью ручной настройки, либо с помощью DHCPv4, то он может просто посмотреть на 24 наиболее значимых бита каждого адреса, сравнить его с 24 наиболее значимыми битами своего собственного адреса и определить, находится ли пункт назначения на сегменте или нет. Двадцать четыре бита IPv4-адреса создают хороший разрыв между третьей и четвертой секциями адреса (каждая секция IPv4-адреса представляет собой 8 бит адресного пространства, в общей сложности 32 бита адресного пространства). Любые два адреса с такими же левыми тремя секциями, что и у A, называемые сетевым адресом, находятся в одном сегменте; любой адрес, которого нет в сегменте. В этом случае сетевой адрес для A и C совпадает, поэтому A будет считать, что C находится в одном сегменте, и, следовательно, будет отправлять пакеты C напрямую, а не отправлять их на маршрутизатор. Для любого пункта назначения, который A считает вне сегмента, он будет отправлять пакеты на IPv4-адрес конечного пункта назначения, но на MAC-адрес шлюза по умолчанию. Это означает, что маршрутизатор, выступающий в качестве шлюза по умолчанию, примет пакет и переключит его на основе IPv4-адреса назначения. Как выбирается шлюз по умолчанию? Он либо настраивается вручную, либо включается в параметр DHCPv4. А что насчет D? Поскольку сетевые части адресов не совпадают, A будет считать, что D находится вне сегмента. В этом случае A отправит любой трафик для D на свой шлюз по умолчанию, которым является B. Когда B получит эти пакеты, он поймет, что A и D достижимы через один и тот же интерфейс (на основе своей таблицы маршрутизации), поэтому он будет отправлять ICMP-перенаправление на A, говоря ему, что нужно отправлять трафик на D напрямую, а не через B. IPv6 представляет собой более сложный набор проблем, которые необходимо решить при выборе шлюза по умолчанию, потому что IPv6 предполагает, что одно устройство может иметь много адресов IPv6, назначенных конкретному интерфейсу. Рисунок ниже демонстрирует это. На рисунке выше предположим, что администратор сети настроил следующие политики: Ни один хост не может подключаться к A, если у него нет адреса в диапазоне адресов 2001: db8: 3e8: 110 ::/64. Ни один хост не может подключиться к D, если у него нет адреса в диапазоне адресов 2001: db8: 3e8: 112 ::/64. Примечание: В реальном мире вы никогда не построили бы такую политику; это надуманная ситуация, чтобы проиллюстрировать проблему, поставленную в сети минимального размера. Гораздо более реальной проблемой такого же типа была бы одноадресная переадресация обратного пути (uRPF). Чтобы эти политики работали, администратор назначил 110::3 и 112::12 хосту C и 111::120 хосту F. Это может показаться странным, но совершенно законно для одного сегмента иметь несколько подсетей IPv6, назначенных в IPv6; также совершенно законно иметь одно устройство с несколькими адресами. На самом деле, в IPv6 существует множество ситуаций, когда одному устройству может быть назначен диапазон адресов. Однако с точки зрения длины префикса нет двух адресов, назначенных C или F, в одной подсети. Из-за этого IPv6 не полагается на длину префикса, чтобы определить, что находится в сегменте, а что нет. Вместо этого реализации IPv6 ведут таблицу всех подключенных хостов, используя запросы соседей, чтобы определить, что находится в сегменте, а что нет. Когда хост хочет отправить трафик из локального сегмента, он отправляет трафик на один из маршрутизаторов, о котором он узнал из объявлений маршрутизатора. Если маршрутизатор получает пакет, к которому, как он знает, другой маршрутизатор в сегменте имеет лучший маршрут (поскольку у маршрутизаторов есть таблицы маршрутизации, которые говорят им, какой путь выбрать к какому-либо конкретному месту назначения), маршрутизатор отправит сообщение перенаправления ICMPv6, сообщающее хосту использовать какой-либо другой маршрутизатор первого перехода для достижения пункта назначения. В следующей статьей мы поговорим про пакетную коммутацию.
img
Как известно, в телефонии существует два основных вида перевода (или трансфера - transfer) входящих звонков, это: Attendant Transfer/ consultative transfer - Перевод звонка, при котором оператор, получив информацию от звонящего, ставит звонок на удержание, затем инициирует второй вызов третьей стороне (абоненту, с которым хочет соединиться звонящий), уведомляет о входящем вызове и лишь после разрешения третьей стороны, соединяет с вызывающим абонентом. После этого, оператор кладет трубку и больше никак не влияет на переведенный вызов. Таким образом, оператор остается уверенным в том, что звонящий соединен с нужным абонентом. В случае, если у оператора не получается дозвониться до вызываемого абонента или он сообщает, что не может в данный момент принять звонок, оператор снимает звонящего с удержания и просит его перезвонить позднее. Blind Transfer - Даже из названия становится понятно, что данный вид перевода является “слепым”, т.е оператор переводит звонок, не уведомляя третью сторону в входящем вызове. Не трудно догадаться, что если вызываемый абонент занят или не отвечает, то вызов попросту обрывается. Согласитесь, ситуация крайне нежелательная, клиентам приходится заново набирать номер, общаться с оператором, объяснять, что разговора не состоялось и т.д. Теряется время, лояльность клиентов и интерес. В IP телефонии на базе Asterisk с данной проблемой познакомились, когда начали осуществлять миграцию с аналоговых АТС. Дело в том, что аналоговые АТС по умолчанию поддерживают так называемый Transfer Recall. Данный функционал заставляет АТС перезванивать оператору, если звонок между вызывающим и вызываемым абонентами, по каким то причинам не состоялся. Оператор, в свою очередь, просил вызывающего абонента перезвонить. Проблема с потерянными вызовами после “слепого” перевода имела место быть вплоть до Asterisk версии 1.6, когда в файл feature.conf в Attended Transfer (atxfer) не был введен дополнительный функционал atxferdropcall , со значениями yes и no atxferdropcall = yes - Звонок не будет возобновлен после неудачного перевода atxferdropcall = no – Звонок будет возобновлен после неудачного перевода По умолчанию в Asterisk данная переменная имеет значение yes. Таким образом, чтобы решить проблемы с потерянными вызовами при переводе, нужно просто изменить файл feature.conf следующим образом: [general] parkext => *700 parkpos => 701-720 context => parkedcalls parkedcalltransfers = caller transferdigittimeout => 1 xfersound = beep xferfailsound = beeperr atxfernoanswertimeout = 15 atxferdropcall = no atxferloopdelay = 10 atxfercallbackretries = 2 [featuremap] blindxfer => * atxfer => # Где, atxfernoanswertimeout - Время, которое необходимо для дозвона обратно; atxfercallbackretries - Количество попыток повторного дозвона
ВЕСЕННИЕ СКИДКИ
40%
50%
60%
До конца акции: 30 дней 24 : 59 : 59